瀏覽代碼

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

zhouj1203@hotmail.com 1 年之前
父節點
當前提交
7b6ec372f1
共有 54 個文件被更改,包括 700 次插入508 次删除
  1. 32 7
      TEAMModelBI/ClientApp/src/view/issueCoupons/crteadCoupon.vue
  2. 3 3
      TEAMModelBI/TEAMModelBI.csproj
  3. 4 3
      TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs
  4. 11 1
      TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs
  5. 3 3
      TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj
  6. 19 2
      TEAMModelOS.FunctionV4/TimeTrigger/IESTimerTrigger.cs
  7. 0 1
      TEAMModelOS.SDK/DI/AzureStorage/Inner/AzureBlobModel.cs
  8. 3 0
      TEAMModelOS.SDK/DI/HttpTrigger/WebHookHttpTrigger.cs
  9. 33 90
      TEAMModelOS.SDK/Helper/Common/DateTimeHelper/DateTimeHelper.cs
  10. 5 0
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/GroupChange.cs
  11. 2 2
      TEAMModelOS.SDK/Models/Cosmos/Common/LearnRecord.cs
  12. 103 0
      TEAMModelOS.SDK/Models/Dtos/Accumulate.cs
  13. 8 1
      TEAMModelOS.SDK/Models/Service/BI/BILogAnalyseService.cs
  14. 0 1
      TEAMModelOS.SDK/Models/Service/FixDataService.cs
  15. 12 7
      TEAMModelOS.SDK/Models/Service/GroupListService.cs
  16. 0 1
      TEAMModelOS.SDK/Models/Service/LessonService.cs
  17. 32 5
      TEAMModelOS.SDK/Models/Service/StudentService.cs
  18. 61 0
      TEAMModelOS.SDK/Models/Service/SystemService.cs
  19. 3 3
      TEAMModelOS.SDK/Models/Service/Third/ThirdService.cs
  20. 3 3
      TEAMModelOS.SDK/TEAMModelOS.SDK.csproj
  21. 12 4
      TEAMModelOS/ClientApp/public/lang/en-US.js
  22. 10 2
      TEAMModelOS/ClientApp/public/lang/zh-CN.js
  23. 150 142
      TEAMModelOS/ClientApp/public/lang/zh-TW.js
  24. 64 104
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperViewBox/LessonTestReport.vue
  25. 9 2
      TEAMModelOS/ClientApp/src/components/student-web/WrongQusetion/AnswerBox.less
  26. 11 7
      TEAMModelOS/ClientApp/src/components/student-web/WrongQusetion/AnswerBox.vue
  27. 10 0
      TEAMModelOS/ClientApp/src/utils/evTools.js
  28. 3 0
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseEditExercise.vue
  29. 5 1
      TEAMModelOS/ClientApp/src/view/evaluation/index/CreateExercises.vue
  30. 22 8
      TEAMModelOS/ClientApp/src/view/evaluation/types/BaseSubjective.vue
  31. 6 0
      TEAMModelOS/ClientApp/src/view/mycourse/MyCourse.vue
  32. 0 1
      TEAMModelOS/Controllers/Analysis/ChangeController.cs
  33. 0 1
      TEAMModelOS/Controllers/Analysis/ClassAnalysisController.cs
  34. 3 3
      TEAMModelOS/Controllers/Both/CourseController.cs
  35. 13 13
      TEAMModelOS/Controllers/Both/GroupListController.cs
  36. 0 1
      TEAMModelOS/Controllers/Both/ScoreCalcController.cs
  37. 2 1
      TEAMModelOS/Controllers/Client/HiTAControlller.cs
  38. 3 3
      TEAMModelOS/Controllers/Client/HiTeachController.cs
  39. 2 1
      TEAMModelOS/Controllers/Client/HiTeachccControlller.cs
  40. 1 1
      TEAMModelOS/Controllers/Common/AreaController.cs
  41. 0 1
      TEAMModelOS/Controllers/Common/ExamController.cs
  42. 1 1
      TEAMModelOS/Controllers/Common/StudyController.cs
  43. 6 6
      TEAMModelOS/Controllers/OpenApi/OpenSchool/ScGroupListController.cs
  44. 1 1
      TEAMModelOS/Controllers/School/ClassController.cs
  45. 1 1
      TEAMModelOS/Controllers/School/SchoolTeacherController.cs
  46. 3 0
      TEAMModelOS/Controllers/Student/StudentController.cs
  47. 2 2
      TEAMModelOS/Controllers/System/CoreController.cs
  48. 2 1
      TEAMModelOS/Controllers/Teacher/InitController.cs
  49. 2 2
      TEAMModelOS/Controllers/Third/Sc/ScController.cs
  50. 9 22
      TEAMModelOS/Controllers/XTest/FixDataController.cs
  51. 4 37
      TEAMModelOS/Controllers/XTest/TestController.cs
  52. 4 4
      TEAMModelOS/TEAMModelOS.csproj
  53. 1 1
      TEAMModelOS/appsettings.Development.json
  54. 1 1
      TEAMModelOS/appsettings.json

+ 32 - 7
TEAMModelBI/ClientApp/src/view/issueCoupons/crteadCoupon.vue

@@ -10,12 +10,14 @@
                 </el-radio-group>
             </el-form-item>
             <el-form-item v-if="!detailSettingFlag" label="活動票券" prop="eventType">
-                <el-radio-group v-model="eventType" @change="setEventType">
+                <el-radio-group v-model="eventType" @change="setEventType" style="max-width: 1000px;">
                     <el-radio label="hiteach50-3"  border>Hiteach 50 第三階段</el-radio>
                     <el-radio label="hiteach333-1"  border>HiTeach 333 第一階段</el-radio>
                     <el-radio label="hiteach333-3"  border>HiTeach 333 第三階段</el-radio>
                     <el-radio label="hiteachBookSPLicense"  border>HiTeach專書贈送授權</el-radio>
                     <el-radio label="fbGroupOpening"  border>HiTeach社團開幕活動</el-radio>
+                    <el-radio label="giftWebIRS501M"  border>贈送WEBIRS50一個月</el-radio>
+                    <el-radio label="giftSmart1Y"  border>贈送智慧評分一年</el-radio>
                 </el-radio-group>
             </el-form-item>
             <el-form-item v-if="detailSettingFlag" label="票券類型" prop="couponType" >
@@ -94,8 +96,8 @@
                             </div>
                         </template>
                         <div style="text-align: left;">
-                            票券標題:<el-input v-model="info.n" :readonly="!detailSettingFlag"/>
-                            連結:<el-input v-model="info.u" :readonly="!detailSettingFlag"/>
+                            票券標題:<el-input v-model="info.n"/>
+                            連結:<el-input v-model="info.u"/>
                         </div>
                         <template #footer>
                             <div style="display: flex;justify-content: center;">
@@ -226,7 +228,7 @@ const setEventType = (type)=>{
                     val:''
                 }
             ]
-            crtCouponForm.rule[0].b = '901003'
+            crtCouponForm.rule[0].b = '901009'
             crtCouponForm.info[0].l = 'zh-tw' 
             crtCouponForm.info[0].n = '教師自主增能三'
             crtCouponForm.info[0].u = 'https://www.habook.com/zh-tw/event.php?act=view&id=170'
@@ -321,6 +323,28 @@ const setEventType = (type)=>{
             crtCouponForm.info[2].n = 'Facebook Group Opening'
             crtCouponForm.info[2].u = 'https://www.habook.com/en/'
         break
+        case 'giftWebIRS501M':
+            crtCouponForm.couponType =  'Event'
+            crtCouponForm.eventName = 'giftWebIRS501M'
+            crtCouponForm.rule[0].b = '901004'
+            crtCouponForm.info[0].l = 'zh-tw' 
+            crtCouponForm.info[0].u = 'https://www.habook.com/zh-tw'
+            crtCouponForm.info[1].l = 'zh-cn'
+            crtCouponForm.info[1].u = 'https://www.habook.com.cn/'
+            crtCouponForm.info[2].l = 'en-us'
+            crtCouponForm.info[2].u = 'https://www.habook.com/en/'
+        break
+        case 'giftSmart1Y':
+            crtCouponForm.couponType =  'Event'
+            crtCouponForm.eventName = 'giftSmart1Y'
+            crtCouponForm.rule[0].b = '901005'
+            crtCouponForm.info[0].l = 'zh-tw' 
+            crtCouponForm.info[0].u = 'https://www.habook.com/zh-tw'
+            crtCouponForm.info[1].l = 'zh-cn'
+            crtCouponForm.info[1].u = 'https://www.habook.com.cn/'
+            crtCouponForm.info[2].l = 'en-us'
+            crtCouponForm.info[2].u = 'https://www.habook.com/en/'
+        break        
     }
 }
 
@@ -361,8 +385,8 @@ const howList = [
 ]
 
 const ruleBList = [
-    { label: "AI文字分析模組(展延)", val: "901001"},
-    { label: "AI蘇格拉底小數據(展延)", val: "901002"},
+    { label: "AI文字分析模組(一年)", val: "901001"},
+    { label: "AI蘇格拉底小數據(一年)", val: "901002"},
     { label: "Web IRS 50人 (展延3個月)", val: "901003"},
     { label: "Web IRS 50人 (延長1個月)", val: "901004"},
     { label: "智慧評分 (一年)", val: "901005"},
@@ -372,7 +396,8 @@ const ruleBList = [
     { label: "HiTeachCC-200連線數(展延)", val: "903004"},
     { label: "小組協作(一年)", val: "901006"},
     { label: "AI GPT(一年)", val: "901007"},
-    { label: "智慧評分 (三個月)", val: "901008"}
+    { label: "智慧評分 (三個月)", val: "901008"},
+    { label: "Web IRS 50人(3個月+75天- 50券STEP3專用)", val: "901009"}    
 ]
 
 const crtCouponForm = reactive({

+ 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.2402.28</Version>
-		<AssemblyVersion>5.2402.28.1</AssemblyVersion>
-		<FileVersion>5.2402.28.1</FileVersion>
+		<Version>5.2403.6</Version>
+		<AssemblyVersion>5.2403.6.1</AssemblyVersion>
+		<FileVersion>5.2403.6.1</FileVersion>
 		<Description>TEAMModelBI(BI)</Description>
 		<PackageReleaseNotes>BI版本说明版本切换标记2022000908</PackageReleaseNotes>
 		<PackageId>TEAMModelBI</PackageId>

+ 4 - 3
TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs

@@ -37,6 +37,7 @@ using TEAMModelOS.Models;
 using Microsoft.AspNetCore.Razor.TagHelpers;
 using HtmlAgilityPack;
 using Azure.Storage.Blobs;
+using System.ComponentModel;
 
 namespace TEAMModelOS.FunctionV4
 {
@@ -807,12 +808,12 @@ namespace TEAMModelOS.FunctionV4
             {// 如果是是非題 正確答案要用true false的方式設定
                 if (questionData.exercise.answer[0] == "A")
                 {
-                    learnRecordItem.Correct = true;
+                    learnRecordItem.Correct = new string[] { "true" };
                 }
                 else
                 {
-                    learnRecordItem.Correct = false;
-                }
+                    learnRecordItem.Correct = new string[] { "false" };
+                }               
             }
             else
             {// 防呆 去html標籤

+ 11 - 1
TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs

@@ -27,7 +27,6 @@ using System.IO;
 using Azure;
 using static TEAMModelOS.SDK.Models.Service.LessonService;
 using DinkToPdf.Contracts;
-using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 using static TEAMModelOS.SDK.StatisticsService;
 using DocumentFormat.OpenXml.Office2010.Excel;
 using DocumentFormat.OpenXml.Wordprocessing;
@@ -44,6 +43,8 @@ using System.Collections.Concurrent;
 using Microsoft.Azure.Amqp.Framing;
 using System.Security.Policy;
 using TEAMModelOS.SDK.Models.Service.BI;
+using TEAMModelOS.SDK.Models.Dtos;
+using System.ServiceModel.Channels;
 
 namespace TEAMModelOS.FunctionV4.ServiceBus
 {
@@ -495,6 +496,15 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                 //await _dingDing.SendBotMsg($"名单变化{msg}", GroupNames.成都开发測試群組);
                 var jsonMsg = JsonDocument.Parse(msg);
                 GroupChange groupChange = msg.ToObject<GroupChange>();
+                int add = groupChange.tmdjoin.Count-groupChange.tmdleave.Count+groupChange.stujoin.Count-groupChange.stuleave.Count;
+                if (groupChange.scope.Equals("private") && (groupChange.type.Equals("student") || groupChange.type.Equals("class") || groupChange.type.Equals("teach")))
+                {
+                    await SystemService.RecordAccumulateData(_azureRedis, _dingDing, new Accumulate { client=groupChange.client, count=add, id= groupChange.listid, scope="teacher", key= "grouplist", name=groupChange.name, target= groupChange.creatorId });
+                }
+                if (groupChange.scope.Equals("school")  && (groupChange.type.Equals("student") || groupChange.type.Equals("class") || groupChange.type.Equals("teach")))
+                {
+                    await SystemService.RecordAccumulateData(_azureRedis,_dingDing, new Accumulate { client=groupChange.client, count=add, id= groupChange.listid, scope="school", key= "grouplist", name=groupChange.name, target=groupChange.school });
+                }
                 //名单变动修改学生课程关联信息
                 //await StuListService.FixStuCourse(client, stuListChange);
                 //Vote投票 Survey问卷 Exam评测 Learn学习活动 Homework作业活动

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

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

+ 19 - 2
TEAMModelOS.FunctionV4/TimeTrigger/IESTimerTrigger.cs

@@ -102,7 +102,16 @@ namespace TEAMModelOS.FunctionV4.TimeTrigger
                                 json.TryGetProperty("url", out JsonElement base64);
                                 using (MemoryStream ms = new MemoryStream(Convert.FromBase64String($"{base64}")))
                                 {
-                                    image = await _azureStorage.GetBlobContainerClient("0-public").UploadFileByContainer(ms, $"visitCnt/{y}{m}{d}", $"{y}{m}{d}{h}.png", false);
+                                    TimeZoneInfo localTimezone = TimeZoneInfo.Local;
+                                    var Hours = localTimezone.BaseUtcOffset.Hours;
+                                    var nowTime = DateTimeOffset.UtcNow;
+                                    if (Hours!=0)
+                                    {
+                                        //有时差
+                                        nowTime =  DateTimeOffset.UtcNow.AddHours(8-Hours);
+                                    }
+                                    image = await _azureStorage.GetBlobContainerClient("0-public").UploadFileByContainer(ms, $"visitCnt/{nowTime.ToString("yyyyMMdd")}", $"{nowTime.ToString("yyyyMMddHH")}.png", false);
+                                    //image = await _azureStorage.GetBlobContainerClient("0-public").UploadFileByContainer(ms, $"visitCnt/{y}{m}{d}", $"{y}{m}{d}{h}.png", false);
                                 }
 
                             }
@@ -144,7 +153,15 @@ namespace TEAMModelOS.FunctionV4.TimeTrigger
                                     dayJson.TryGetProperty("url", out JsonElement dayBase64);
                                     using (MemoryStream dayMs = new(Convert.FromBase64String($"{dayBase64}")))
                                     {
-                                        dayImage = await _azureStorage.GetBlobContainerClient("0-public").UploadFileByContainer(dayMs, $"visitCnt/{ptY}{ptM}{ptD}", "days.png", false);
+                                        TimeZoneInfo localTimezone = TimeZoneInfo.Local;
+                                        var Hours = localTimezone.BaseUtcOffset.Hours;
+                                        var nowTime = DateTimeOffset.UtcNow;
+                                        if (Hours!=0)
+                                        {
+                                            //有时差
+                                            nowTime =  DateTimeOffset.UtcNow.AddHours(8-Hours);
+                                        }
+                                        dayImage = await _azureStorage.GetBlobContainerClient("0-public").UploadFileByContainer(dayMs, $"visitCnt/{nowTime.ToString("yyyyMMdd")}", "days.png", false);
                                     }
                                 }
                             }

+ 0 - 1
TEAMModelOS.SDK/DI/AzureStorage/Inner/AzureBlobModel.cs

@@ -4,7 +4,6 @@ using Microsoft.Azure.Cosmos.Table;
 using System;
 using System.ComponentModel.DataAnnotations;
 using System.IO;
-using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 
 namespace TEAMModelOS.SDK.Module.AzureBlob.Container
 {

+ 3 - 0
TEAMModelOS.SDK/DI/HttpTrigger/WebHookHttpTrigger.cs

@@ -100,6 +100,7 @@ namespace TEAMModelOS.SDK.DI
             GroupChange data = null;
             if (json.TryGetProperty("data", out JsonElement _data)){
                 data= _data.ToObject<GroupChange>();
+                data.client="web";
             }
             (List<BizConfig> businessConfigs, List<(List<string> urls, string head, string token, BizConfig config)> webhooks ) = await WebHookService.GetRequestData(_data, _azureCosmos,_azureRedis,_azureStorage);
             if (webhooks.IsNotEmpty() && !string.IsNullOrWhiteSpace(data.school))
@@ -110,6 +111,8 @@ namespace TEAMModelOS.SDK.DI
                     {
                         await WebHookService.Send(new
                         {
+                            data.name,
+                            data.client,
                             data.status,
                             data.type,
                             data.listid,

+ 33 - 90
TEAMModelOS.SDK/Helper/Common/DateTimeHelper/DateTimeHelper.cs

@@ -2,20 +2,10 @@ using System;
 using System.Collections.Generic;
 using System.Text;
 
-namespace TEAMModelOS.SDK.Helper.Common.DateTimeHelper
+namespace TEAMModelOS.SDK
 {
     public static class DateTimeHelper
     {
-        /// <summary>
-        /// 日期转换为时间戳(时间戳单位秒)
-        /// </summary>
-        /// <param name="TimeStamp"></param>
-        /// <returns></returns>
-        public static long ConvertToTimeStamp10(DateTime time)
-        {
-            DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
-            return (long)(time.AddHours(-8) - Jan1st1970).TotalMilliseconds / 1000;
-        }
 
         public static DateTime FromUnixTimestamp(this long unixtime)
         {
@@ -23,102 +13,55 @@ namespace TEAMModelOS.SDK.Helper.Common.DateTimeHelper
             return sTime.AddMilliseconds(unixtime);
         }
 
-        public static DateTime FromUnixTimestampOffSet(this long unixtime, int offset)
-        {
-            DateTime sTime = TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1), TimeZoneInfo.Utc, TimeZoneInfo.Local);
-            int serverOffset = (int)TimeZoneInfo.Local.GetUtcOffset(DateTime.Now).TotalMinutes;
-            int subOffset = offset - serverOffset;
-            return sTime.AddMilliseconds(unixtime).AddMinutes(subOffset);
-        }
+         
         public static long ToUnixTimestamp(this DateTime datetime)
         {
             //DateTime sTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
             DateTime sTime = TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1), TimeZoneInfo.Utc, TimeZoneInfo.Local);
             return (long)(datetime - sTime).TotalMilliseconds;
         }
+       
         /// <summary>
-        /// 获取当前cpu振荡时间戳 17位数
-        /// </summary>
-        /// <returns></returns>
-        public static long GetCPUMillisecond()
-        {
-            return DateTime.Now.ToUniversalTime().Ticks - 621355968000000000;
-        }
-        /// <summary>
-        /// 获取标准毫秒级时间戳 13位数
-        /// </summary>
-        /// <returns></returns>
-        public static long GetMillisecond()
-        {
-            return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000;
-        }
-        /// <summary>
-        /// 获取当前年
-        /// </summary>
-        /// <returns></returns>
-        public static int GetCurrentYear()
-        {
-            return DateTime.Now.Year;
-        }
-        /// <summary>
-        /// 获取当前月份
-        /// </summary>
-        /// <returns></returns>
-        public static int GetCurrentMonth()
-        {
-            return DateTime.Now.Month;
-        }
-        /// <summary>
-        /// 获取星期几
-        /// </summary>
-        /// <returns></returns>
-        public static DayOfWeek GetCurrentDayOfWeek()
-        {
-            return DateTime.Now.DayOfWeek;
-        }
-        /// <summary>
-        /// 获取本年第几天
-        /// </summary>
-        /// <returns></returns>
-        public static int GetCurrentDayOfYear()
-        {
-            return DateTime.Now.DayOfYear;
-        }
-        /// <summary>
-        /// 获取当前小时
-        /// </summary>
-        /// <returns></returns>
-        public static int GetCurrentHour()
-        {
-            return DateTime.Now.Hour;
-        }
-        /// <summary>
-        /// 获取当前分钟
+        /// 获得 GMT+8 时间
         /// </summary>
         /// <returns></returns>
-        public static int GetCurrentMinute()
+        public static DateTime GetGMTTime(this DateTime dateTime, int GMT = 8)
         {
-            return DateTime.Now.Minute;
+            //SystemTimeZoneById  :  https://learn.microsoft.com/zh-cn/previous-versions/windows/embedded/ms912391(v=winembedded.11)
+            //TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");//设置时区
+            //DateTime easternTime = TimeZoneInfo.ConvertTimeFromUtc(dateTime, easternZone);
+            //return easternTime;
+
+
+            //处理UTC时差
+            TimeZoneInfo localTimezone = TimeZoneInfo.Local;
+            var Hours = localTimezone.BaseUtcOffset.Hours;
+            if (Hours!=0)
+            {
+                //有时差
+                dateTime = dateTime.AddHours(GMT-Hours);
+            }
+            return dateTime;
         }
         /// <summary>
-        /// 获取当前秒
+        /// 默认东八区+8
         /// </summary>
+        /// <param name="dateTime"></param>
+        /// <param name="GMT"></param>
         /// <returns></returns>
-        public static int GetCurrentSecond()
+        public static DateTimeOffset GetGMTTime(this DateTimeOffset dateTime,int GMT=+8)
         {
-            return DateTime.Now.Second;
+            //处理UTC时差
+            TimeZoneInfo localTimezone = TimeZoneInfo.Local;
+            var Hours = localTimezone.BaseUtcOffset.Hours;
+            if (Hours!=0)
+            {
+                //有时差
+                dateTime = dateTime.AddHours(GMT-Hours);
+            }
+            return dateTime;
         }
-        /// <summary>
-        /// 获得 GMT+8 时间
-        /// </summary>
-        /// <returns></returns>
-        public static DateTime ChinaTime()
-        {
 
-            TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");//设置时区
-            DateTime easternTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, easternZone);
-            return easternTime;
-        }
         public static  int getDays(int year) { 
             int day = 0;
             for (int i = 0;i<=12;i++) {

+ 5 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/GroupChange.cs

@@ -56,5 +56,10 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public string status { get; set; } = "upsert";
         public string periodId { get; set; }
+        /// <summary>
+        /// web  hiteach hita
+        /// </summary>
+        public string client { get; set; }
+        public string name { get; set; }
     }
 }

+ 2 - 2
TEAMModelOS.SDK/Models/Cosmos/Common/LearnRecord.cs

@@ -31,9 +31,9 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         public string Desc { get; set; }
         // 知識點陣列, 裡面放字串, 相當於關鍵詞
         public List<string> Points { get; set; }
-        // 知識點陣列, 裡面放字串, 相當於關鍵詞
+        //正確答案, 複選可以放多個
         public object Correct { get; set; }
-        // 知識點陣列, 裡面放字串, 相當於關鍵詞
+        //選項內容, 純文字, 沒有就放空的
         public List<ChoicesItem> Choices { get; set; }
         // 考試卷題數, 若無放 null
         public int? ExamQuesQty { get; set; }

+ 103 - 0
TEAMModelOS.SDK/Models/Dtos/Accumulate.cs

@@ -0,0 +1,103 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS.SDK.Models.Dtos
+{
+    public class Accumulate
+    {
+
+        /// <summary>
+        /// course,课程
+        /// exam 评测
+        /// homework 作业
+        /// login_school_student
+        /// login_student
+        /// login_school_teacher
+        /// login_teacher
+        /// </summary>
+        public string key { get; set; }
+        /// <summary>
+        /// 教师,学校管理员,系统管理员(包含钉钉)
+        /// </summary>
+        public string target { get; set; }
+        /// <summary>
+        /// 业务id
+        /// </summary>
+        public string id { get; set; }
+        /// <summary>
+        /// 名称
+        /// </summary>
+        public string name { get; set; }
+        /// <summary>
+        /// teacher发送给教师的  school 发送给学校管理员的   system发送给系统管理员的
+        /// </summary>
+        public string scope { get; set; }
+        public int count { get; set; } = 1;
+        /// <summary>
+        /// web,hiteach,hita
+        /// </summary>
+        public string client {  get; set; }
+
+        //Accumulate:Keys:Day
+
+        //Accumulate:Keys:Week
+
+        /*加入的人数
+         * Accumulate:Daily:teacher:grouplist:yyyyddMM:==>1595321354-grouplistId=>count
+        key:grouplist
+        target:1595321354
+        id:grouplistId
+        scope:teacher
+        name:名单名称
+        count:8
+         */
+        /*作业提交人数
+         * Accumulate:Daily:teacher:homework:yyyyddMM:==>1595321354-homeworkId=>count
+        key:homework
+        target:1595321354
+        id:homeworkId
+        scope:teacher
+        name:作业名称
+        count:8
+         */
+        /*评测完成人数
+         * Accumulate:Daily:teacher:exam:yyyyddMM:==>1595321354-examId=>count
+        key:exam
+        target:1595321354
+        id:examId
+        scope:teacher
+        name:作业名称
+        count:8
+         */
+        /*学生登入人数,scope学校的统一发送给管理员scope:system,发送给系统管理员,及钉钉
+        * Accumulate:Daily:school:login_student:yyyyddMM:==>hbcn-hbcn=>count
+        key:login_student
+        target:hbcn,root
+        id:hbcn,ies
+        scope:school,system
+        name:学校名称
+        count:8
+        */
+        /*教师登入人数,scope学校的统一发送给管理员scope:system,发送给系统管理员,及钉钉
+        * Accumulate:Daily:school:login_teacher:yyyyddMM:==>hbcn-hbcn=>count
+        key:login_teacher
+        target:hbcn,root
+        id:hbcn,ies
+        scope:school,system
+        name:学校名称
+        count:8
+        */
+        /*开课数量,scope学校的统一发送给管理员,scope:system,发送给系统管理员,及钉钉
+       * Accumulate:Daily:school:lesson:yyyyddMM:==>hbcn-hbcn=>count
+       key:lesson
+       target:hbcn,root
+       id:hbcn,ies
+       scope:school,system
+       name:学校名称
+       count:8
+       */
+    }
+}

+ 8 - 1
TEAMModelOS.SDK/Models/Service/BI/BILogAnalyseService.cs

@@ -101,8 +101,15 @@ namespace TEAMModelOS.SDK.Models.Service.BI
          {
             List<RecCnt> recCnts = new();
             List<string> urls = new();
-
+            TimeZoneInfo localTimezone = TimeZoneInfo.Local;
+            var Hours = localTimezone.BaseUtcOffset.Hours;
             DateTimeOffset dtime = DateTimeOffset.UtcNow;
+            if (Hours!=0)
+            {
+                //有时差
+                dtime =  DateTimeOffset.UtcNow.AddHours(8-Hours);
+            }
+          
             string cDay = dtime.ToString("yyyyMMdd");
 
             //天api

+ 0 - 1
TEAMModelOS.SDK/Models/Service/FixDataService.cs

@@ -16,7 +16,6 @@ using System.Dynamic;
 using Newtonsoft.Json;
 using TEAMModelOS.Models;
 using Azure.Storage.Blobs.Models;
-using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 using DinkToPdf.Contracts;
 
 namespace TEAMModelOS.SDK.Models.Service

+ 12 - 7
TEAMModelOS.SDK/Models/Service/GroupListService.cs

@@ -16,6 +16,7 @@ using TEAMModelOS.SDK.Models;
 using System.Net.Http;
 using DocumentFormat.OpenXml.Drawing.Charts;
 using System.Reflection;
+using TEAMModelOS.SDK.Models.Service;
 
 
 namespace TEAMModelOS.SDK
@@ -230,10 +231,11 @@ namespace TEAMModelOS.SDK
             }
         }
 
-        public static async Task DeleteGrouplistEvent(string  id , string code,string  tbname ,CosmosClient client, IConfiguration _configuration, AzureServiceBusFactory _serviceBus)
+        public static async Task DeleteGrouplistEvent(string  id , string code,string  tbname ,CosmosClient client, IConfiguration _configuration, AzureServiceBusFactory _serviceBus,string _client)
         {
-            GroupChange change = new GroupChange();
+            
             GroupList groupList = await client.GetContainer(Constant.TEAMModelOS, tbname).ReadItemAsync<GroupList>(id.ToString(), new PartitionKey(code));
+            GroupChange change = new GroupChange() { client=_client,name=groupList.name};
             var tleave = groupList.members.FindAll(x => x.type == 1);
             if (tleave.IsNotEmpty())
             {
@@ -446,7 +448,7 @@ namespace TEAMModelOS.SDK
         /// <param name="type"></param>
         /// <param name="school"></param>
         /// <returns></returns>
-        public static async Task<(int status, GroupList stuList,Member member)> CodeJoinList(CosmosClient client,AzureRedisFactory _azureRedis, string _stuListNo, string userid, int type, string school,int year,string name ,string picture,string lang,int seatNo, string courseId= null)
+        public static async Task<(int status, GroupList stuList,Member member)> CodeJoinList(CosmosClient client,AzureRedisFactory _azureRedis, string _stuListNo, string userid, int type, string school,int year,string name ,string picture,string lang,int seatNo, string courseId= null,string _client="web")
         {
             var queryNo = $"SELECT  value(c)  FROM c where  c.no ='{_stuListNo}'";
             (int status, GroupList stuList,Member member) data = (-1, null,null);
@@ -455,7 +457,7 @@ namespace TEAMModelOS.SDK
                 await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<GroupList>(queryText: queryNo,
                 requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList-{school}") }))
                 {
-                    data = JoinList(item, userid, type, school,year,seatNo);
+                     data = await JoinList(_azureRedis, item, userid, type, school,year,seatNo,_client:_client);
                     break;
                 }
             }
@@ -519,7 +521,7 @@ namespace TEAMModelOS.SDK
                     //状态=5 ,人数已满
                     return (5, item, null);
                 }
-                data = JoinList(item, userid, type, school,year,seatNo);
+                data =await JoinList(_azureRedis, item, userid, type, school,year,seatNo, _client: _client);
                 //TODO 需要考虑已经通过别的途径加入名单,但是缓存数据仍记录数据的问题。 还要考虑手动加入过的。或者在获取名未加入名单成员的临时缓存数据的时候过滤已经加入的。
                 break;
             }
@@ -555,7 +557,7 @@ namespace TEAMModelOS.SDK
             public int seatNo { get; set; }
            public List<IdName> courses  { get; set; }= new List<IdName>();
         }
-        public static (int status, GroupList stuList, Member member) JoinList(GroupList stuList, string userid, int type, string school, int year, int seatNo = 0)
+        public static async Task<(int status, GroupList stuList, Member member)> JoinList(AzureRedisFactory azureRedis, GroupList stuList, string userid, int type, string school, int year, int seatNo = 0,string _client="web")
         {
             
             Member member = null;
@@ -586,6 +588,7 @@ namespace TEAMModelOS.SDK
                             status = 0;
                             member = new Member { id = userid, type = type, irs = $"{seatNo}", no =  $"{seatNo}", year=year,manual=1 };
                             stuList.members.Add(member);
+                           
                         }
                     }
                     else if (type == 2)
@@ -675,7 +678,7 @@ namespace TEAMModelOS.SDK
             return (status, stuList, member);
         }
 
-        public static async Task<GroupList> UpsertList(GroupList list, AzureCosmosFactory _azureCosmos, IConfiguration _configuration, AzureServiceBusFactory _serviceBus)
+        public static async Task<GroupList> UpsertList(GroupList list, AzureCosmosFactory _azureCosmos, IConfiguration _configuration, AzureServiceBusFactory _serviceBus,string _client )
         {
             bool isnew = false;
             var client = _azureCosmos.GetCosmosClient();
@@ -721,6 +724,8 @@ namespace TEAMModelOS.SDK
             {
                 GroupChange change = new GroupChange()
                 {
+                    name=list.name,
+                    client=_client,
                     type = list.type,
                     listid = list.id,
                     scope = list.scope,

+ 0 - 1
TEAMModelOS.SDK/Models/Service/LessonService.cs

@@ -17,7 +17,6 @@ using System.Text.Json;
 using System.Threading.Tasks;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
 using TEAMModelOS.SDK.Models.Cosmos.OpenEntity;
 using TEAMModelOS.SDK.Services;

+ 32 - 5
TEAMModelOS.SDK/Models/Service/StudentService.cs

@@ -2,6 +2,7 @@
 using Azure.Cosmos;
 using Azure.Messaging.ServiceBus;
 using DocumentFormat.OpenXml.Drawing;
+using DocumentFormat.OpenXml.Drawing.Charts;
 using DocumentFormat.OpenXml.Office2010.Excel;
 using DocumentFormat.OpenXml.Spreadsheet;
 using DocumentFormat.OpenXml.VariantTypes;
@@ -407,6 +408,8 @@ namespace TEAMModelOS.SDK
                             {
                                 GroupChange change = new GroupChange
                                 {
+
+                                    client="web",
                                     scope = "school",
                                     school = schoolId,
                                     type = "student",
@@ -442,6 +445,7 @@ namespace TEAMModelOS.SDK
                             {
                                 GroupChange change = new GroupChange
                                 {
+                                    client="web",
                                     scope = "school",
                                     school = schoolId,
                                     type = "student",
@@ -480,6 +484,7 @@ namespace TEAMModelOS.SDK
                                 {
                                     GroupChange change = new GroupChange
                                     {
+                                        client="web",
                                         scope = "school",
                                         school = schoolId,
                                         type = "student",
@@ -511,6 +516,7 @@ namespace TEAMModelOS.SDK
                                 {
                                     GroupChange change = new GroupChange
                                     {
+                                        client="web",
                                         scope = "school",
                                         school = schoolId,
                                         type = "student",
@@ -558,6 +564,7 @@ namespace TEAMModelOS.SDK
                             {
                                 GroupChange change = new GroupChange
                                 {
+                                    client="web",
                                     scope = "school",
                                     school = schoolId,
                                     type = "student",
@@ -602,7 +609,8 @@ namespace TEAMModelOS.SDK
                             else
                             {
                                 GroupChange change = new GroupChange
-                                {
+                                {   
+                                    client = "web",
                                     scope = "school",
                                     school = schoolId,
                                     type = "student",
@@ -638,6 +646,7 @@ namespace TEAMModelOS.SDK
                             {
                                 GroupChange change = new GroupChange
                                 {
+                                    client="web",
                                     scope = "school",
                                     school = schoolId,
                                     type = "student",
@@ -676,6 +685,7 @@ namespace TEAMModelOS.SDK
                                 {
                                     GroupChange change = new GroupChange
                                     {
+                                        client="web",
                                         scope = "school",
                                         school = schoolId,
                                         type = "student",
@@ -707,6 +717,7 @@ namespace TEAMModelOS.SDK
                                 {
                                     GroupChange change = new GroupChange
                                     {
+                                        client="web",
                                         scope = "school",
                                         school = schoolId,
                                         type = "student",
@@ -754,6 +765,7 @@ namespace TEAMModelOS.SDK
                             {
                                 GroupChange change = new GroupChange
                                 {
+                                    client="web",
                                     scope = "school",
                                     school = schoolId,
                                     type = "student",
@@ -775,15 +787,30 @@ namespace TEAMModelOS.SDK
                     }
                 }
             }
+            List<Class> classes = new List<Class>();
+            if (dictChange.Keys.Count>0)
+            {
+                string insql = string.Join(",", dictChange.Keys.Select(x => $"'{x}'"));
+                var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").GetList<Class>($"select     c.id,c.name   from c where c.id in ({insql})", $"Class-{schoolId}");
+                if (result.list.IsNotEmpty())
+                {
+                    classes.AddRange(result.list);
+                }
+            }
             foreach (var changed in dictChange.Keys)
             {
                 var change = dictChange[changed];
                 if (change.stujoin.Count != 0 || change.stuleave.Count != 0)
                 {
-                    var messageChange = new ServiceBusMessage(change.ToJsonString());
-                    messageChange.ApplicationProperties.Add("name", "GroupChange");
-                    var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
-                    await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange);
+                   var clazz=  classes.Find(x => x.id.Equals(changed));
+                    if (clazz!=null) {
+                        change.name=clazz.name;
+                        var messageChange = new ServiceBusMessage(change.ToJsonString());
+                        messageChange.ApplicationProperties.Add("name", "GroupChange");
+                        var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
+                        await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange);
+                    }
+                    
                 }
             }
 

+ 61 - 0
TEAMModelOS.SDK/Models/Service/SystemService.cs

@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Models.Dtos;
+using static OpenXmlPowerTools.RevisionProcessor;
+
+namespace TEAMModelOS.SDK.Models.Service
+{
+    public static class SystemService
+    {
+        public static async Task RecordAccumulateData(AzureRedisFactory azureRedis,DingDing dingDing, Accumulate accumulate)
+        {
+            if (!string.IsNullOrWhiteSpace(accumulate.key)  && !string.IsNullOrWhiteSpace(accumulate.target) &&
+                !string.IsNullOrWhiteSpace(accumulate.id) && !string.IsNullOrWhiteSpace(accumulate.name) &&
+                !string.IsNullOrWhiteSpace(accumulate.scope) &&  !string.IsNullOrWhiteSpace(accumulate.client))
+            {
+                await RecordAccumulateData(azureRedis, accumulate.key, accumulate.target, accumulate.id, accumulate.name, accumulate.scope, accumulate.client, accumulate.count);
+            }
+            else {
+                await dingDing.SendBotMsg($"IES累计数据变更统计参数异常,{accumulate.ToJsonString()}", GroupNames.成都开发測試群組);
+            }
+        }
+
+        /// <summary>
+        /// 记录累计数据
+        /// </summary>
+        public static async Task RecordAccumulateData(AzureRedisFactory azureRedis, string key, string target, string id, string name, string scope, string client,int count) 
+        {
+            if (!string.IsNullOrWhiteSpace(key)  && !string.IsNullOrWhiteSpace(target) && 
+                !string.IsNullOrWhiteSpace(id) && !string.IsNullOrWhiteSpace(name) && 
+                !string.IsNullOrWhiteSpace(scope)&& !string.IsNullOrWhiteSpace(client)) {
+                //处理UTC时差
+                 var nowTime = DateTimeOffset.UtcNow.GetGMTTime();
+                var day = nowTime.ToString("yyyyMMdd");
+                ///一周的第一天
+                if (nowTime.DayOfWeek.Equals(DayOfWeek.Monday))
+                {
+                }
+                string redisKey = $"Accumulate:Daily:{scope}:{key}:{day}";
+                string member = $"{target}::{id}::{client}::{name}";
+                await azureRedis.GetRedisClient(8).SortedSetIncrementAsync(redisKey, member, count);
+                //if (key.Equals("lesson")  || key.StartsWith("login_"))
+                //{
+                //    redisKey = $"Accumulate:Daily:ies:{key}:{day}";
+                //    if (scope.Equals("school"))
+                //    {
+                //        member = $"ies::{id}::{name}";
+                //    }
+                //    else {
+                //        member = $"ies::ies::{name}";
+                //    }
+                //    await azureRedis.GetRedisClient(8).SortedSetIncrementAsync(redisKey, member, 1);
+                //}
+            }
+        }
+    }
+}

+ 3 - 3
TEAMModelOS.SDK/Models/Service/Third/ThirdService.cs

@@ -151,14 +151,14 @@ namespace TEAMModelOS.SDK.Models
                                 if (meber == null || !meber.Any())
                                 {
                                     yxtrain[0].members.Add(new Member { id = teacher.id, type = 1, groupId = groupId, groupName = groupName,nickname= nickname });
-                                    await GroupListService.UpsertList(yxtrain[0], _azureCosmos, _configuration, _serviceBus);
+                                    await GroupListService.UpsertList(yxtrain[0], _azureCosmos, _configuration, _serviceBus,"web");
                                 }
                                 else
                                 {
                                     if (string.IsNullOrEmpty(meber.First().groupId) || string.IsNullOrEmpty(meber.First().groupName))
                                     {
                                         meber.ToList().ForEach(x => { x.groupId = groupId; x.groupName = groupName;x.nickname = string.IsNullOrWhiteSpace(x.nickname)? nickname:x.nickname; });
-                                        await GroupListService.UpsertList(yxtrain[0], _azureCosmos, _configuration, _serviceBus);
+                                        await GroupListService.UpsertList(yxtrain[0], _azureCosmos, _configuration, _serviceBus, "web");
                                     }
                                 }
                             }
@@ -191,7 +191,7 @@ namespace TEAMModelOS.SDK.Models
                                     pk = "GroupList",
                                     ttl = -1
                                 };
-                                await GroupListService.UpsertList(groupList, _azureCosmos, _configuration, _serviceBus);
+                                await GroupListService.UpsertList(groupList, _azureCosmos, _configuration, _serviceBus, "web");
                             }
                         }
                     }

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

@@ -2,9 +2,9 @@
 
   <PropertyGroup>
     <TargetFramework>net6.0</TargetFramework>
-    <Version>5.2402.28</Version>
-    <AssemblyVersion>5.2402.28.1</AssemblyVersion>
-    <FileVersion>5.2402.28.1</FileVersion>
+    <Version>5.2403.6</Version>
+    <AssemblyVersion>5.2403.6.1</AssemblyVersion>
+    <FileVersion>5.2403.6.1</FileVersion>
     <PackageReleaseNotes>发版</PackageReleaseNotes>
   </PropertyGroup>
 

+ 12 - 4
TEAMModelOS/ClientApp/public/lang/en-US.js

@@ -1089,7 +1089,7 @@ const LANG_EN_US = {
         copyUrl: 'Copy Link',
         joinMessage1: "Allowed to join the course",
         joinMessage2: "Prohibited to join the course",
-        defaultDesc:'Personal Course on the TEAM Model Cloud',
+        defaultDesc:'Personal Course on the IES TEAM Model Cloud',
         inviteInfo1: 'Invite to join the IES Teacher Personal Course on the TEAM Model Cloud',
         inviteInfo2: 'Course Name:',
         inviteInfo3: 'Course List:',
@@ -1102,6 +1102,7 @@ const LANG_EN_US = {
         createTips2: 'Note: You (not yet a member of a school) can allow students to join the course by entering the course invitation code, scanning the course QR code, or using the invitation link.',
         renameListTitle: 'Edit List Name',
         selectListTips: 'Please select a list',
+        renameRepeat: 'List name is duplicate',
         alreadyExist: ' already existed',
         listAPIErr: 'Failed to get the list',
         rmvListTips: 'Note: The current list is also being used in other courses',
@@ -1704,10 +1705,17 @@ const LANG_EN_US = {
             answerType:{
                 types:'Answer Type',
                 text:'Text',
-                textImage:'TextImage',
-                image:'Image',
+                textImage:'Draw Notes',
+                image:'Picture',
                 file:'File',
-                audio:'Audio'
+                audio: 'Audio',
+                autoScore: 'Automatic Scoring',
+                answerLang: 'Language',
+                us: 'English',
+                zh: 'Mandarin',
+                jp: 'Japanese',
+                kr: 'Korean',
+                hk: 'Cantonese'
             },
             newSchoolItem: 'Create School Question',
             newPrivateItem: 'Create Personal Question',

+ 10 - 2
TEAMModelOS/ClientApp/public/lang/zh-CN.js

@@ -1102,6 +1102,7 @@ const LANG_ZH_CN = {
         createTips2: '温馨提示:您(暂未加入学校)可让学生通过输入课程邀请码、扫描课程二维码、课程链接方式主动加入课程。',
         renameListTitle: '修改名称',
         selectListTips: '请选择名单',
+        renameRepeat: '名单名称重复',
         alreadyExist: '已在课程名单',
         listAPIErr: '名单列表获取失败',
         rmvListTips: '温馨提示:当前名单在其他课程也在使用',
@@ -1706,7 +1707,14 @@ const LANG_ZH_CN = {
                 textImage:'标记',
                 image:'图片',
                 file:'文档',
-                audio:'音频'
+                audio:'音频',
+                autoScore:'自动评分',
+                answerLang:'语言类型',
+                us:'英语',
+                zh:'普通话',
+                jp:'日语',
+                kr:'韩语',
+                hk:'粤语'
             },
             newSchoolItem: '新建学校题目',
             newPrivateItem: '新建个人题目',
@@ -8077,7 +8085,7 @@ const LANG_ZH_CN = {
             text10: '手动分配作品',
             text11: '成绩等级设置',
             text12: '调整参数作品分数',
-            text13: '调整参数确认开始评审后,不可删除已邀请的专家,不可调整评审规则,同时专家可以对作品进行评审,是否确认开始评审?作品分数',
+            text13: '调整参数确认开始评审后,不可删除已邀请的专家,不可调整评审规则,同时专家可以对作品进行评审,是否确认开始评审?',
             text14: '删除专家',
             text15: '确认公示成绩后,参赛者将可以查看成绩排名和个人成绩',
             text16: '是否同时修改模板内容',

+ 150 - 142
TEAMModelOS/ClientApp/public/lang/zh-TW.js

@@ -1089,7 +1089,7 @@ const LANG_ZH_TW = {
         copyUrl: '複製網址',
         joinMessage1: "允許加入課程",
         joinMessage2: "禁止加入課程",
-        defaultDesc:'雲端個人課程',
+        defaultDesc: '雲端個人課程',
         inviteInfo1: '邀請加入醍摩豆雲平臺IES教師個人課程',
         inviteInfo2: '課程名稱:',
         inviteInfo3: '課程名單:',
@@ -1102,6 +1102,7 @@ const LANG_ZH_TW = {
         createTips2: '溫馨提示:您(暫未加入學校)可讓學生透過輸入課程邀請碼、掃描課程QR Code、課程網址方式主動加入課程。 ',
         renameListTitle: '修改名稱',
         selectListTips: '請選擇名單',
+        renameRepeat: '名單名稱重複',
         alreadyExist: '已在課程名單',
         listAPIErr: '名單列表獲取失敗',
         rmvListTips: '溫馨提示:當前名單在其他課程也在使用',
@@ -1709,7 +1710,14 @@ const LANG_ZH_TW = {
                 textImage: '標記',
                 image: '圖片',
                 file: '文檔',
-                audio: '音頻'
+                audio: '音頻',
+                autoScore: '自動評分',
+                answerLang: '語言類型',
+                us: '英語',
+                zh: '國語',
+                jp: '日語',
+                kr: '韓語',
+                hk: '粵語'
             },
             newSchoolItem: '新增學校題目',
             newPrivateItem: '新增個人題目',
@@ -3467,7 +3475,7 @@ const LANG_ZH_TW = {
         },
         registModal: {
             title: '驗證手機',
-            form : {
+            form: {
                 placeholder: {
                     phone: '請輸入手機',
                     pindCode: '請輸入驗證碼'
@@ -3669,7 +3677,7 @@ const LANG_ZH_TW = {
         delete: '刪除',
         view: '查看',
         edit: '編輯',
-        tableIsNaN:'尚無成績表',
+        tableIsNaN: '尚無成績表',
         noNotify: '暫無公告',
         notifyDetail: '公告詳情',
         delNotifyTitle: '刪除公告',
@@ -7729,146 +7737,146 @@ const LANG_ZH_TW = {
             totalTime: '總時間數'
         }
     },
-    scoreCalc:{
-        creatDate:'建立日期',
-        customInput:'手動輸入',
-        onlineClass:'線上課堂',
-        onlineHomeWork:'線上作業',
-        IRSnumber:'IRS',
-        addTableInfo:'請先新增成績表',
-        newTable:'新成績統計表',
-        newProject:'新項目',
-        subItem:'子項目',
-        notRated:'未評分',
-        tableIsNaN:'尚無成績表',
-        isNaN:'內容為空',
-        description1:'底線字',
-        description1_2:'可點擊編輯細項',
-        blueWord:'藍字',
-        canModifyable:'可修改',
-        description2:'可修改內容,(括弧)的數字為分數 x 百分比%的結果',
-        simple_complete:'精簡模式/完整模式',  
-        title:'標題',              
-        name:'姓名',
-        id:'學號',
-        class:'課堂',
-        th_homework:'作業',
-        th_exam:'評量',
-        totalScore:'總評分',
-        PRScore:'PR值',
-        gradesInClass:'課堂細項成績',    
-        attendType: "出席狀態",    
-        attend:'出席',//英文版Attendance
-        point:'記分板',
-        interactiveScore:'互動分',
-        attend2:'出席',//英文版Attend
-        leave:'請假',//英文版leave
-        absence:'缺席',//英文版Abs
-        sickLeave:'病假',//英文版SL
-        personalLeave:'事假',//英文版PL
-        publicLeave:'公假',//英文版PH
-        absence2:'缺席',//英文版Absence
-        sickLeave2:'病假',//英文版Sick leave
-        personalLeave2:'事假',//英文版Personal leave
-        publicLeave2:'公假',//英文版Public holiday
-        isSave:'已存檔',
-        notSave:'未存檔',
-        delete:'刪除',
-        export:'匯出',
-        print:'列印',
-        save:'儲存',
-        scoreCalculation:'成績計算',
-        simpleAttendanceCalculation:'簡單出席計算法',
-        attendanceCalculationMethod:'出席率計算法',
-        customCalculation:'自訂計算',
-        percentageScore:'標準化評分',
-        standardizedsScoring:'百分比評分',
-        customScoring:'自訂評分',
-        calculationDescription1:'教師根據學生的出席情況,直接給予分數。通常是以全勤為標準,缺席一次扣一定分數。',
-        calculationDescription2:'請輸入一次缺席扣多少分數',
-        marks:'分',
-        example:'範例:',
-        attendance:'出席成績',
-        fullMarksAttend:'出席滿分',
-        attendPercentage:'出席百分比',
-        absences:'缺席次數',
-        calculationDescription3:'缺席一次扣 ',
-        calculationFormula:'計算公式',
-        calculationDescription4:'勾選即為缺席狀態:',                   
-        checkOk:'確定',
-        cancel:'取消',
-        calculationDescription5:'根據學生的出席次數計算出席率,再以此作為出席分數的依據。出席率以百分比表示,例如出席率超過90%可得滿分,每低於一個百分點扣一定分數。',
-        calculationDescription6:'每缺席1% 扣',
-        attendanceOver:'出席率超過',
-        isFullMark:'% 為滿分',
-        classGrades:'課堂成績:',
-        totalNumberClasses:'課堂總次數',
-        attendQwen:'出席次數', 
-        formula:'公式:',
-        calculationDescription7:'請依照下列變數填寫計算公式:',
-        numberOfSick:'病假次數',
-        numberOfPerson:'事假次數',
-        numberOfPublic:'公假次數',
-        calculationDescription8:'公式範例(以下直接以出席率為出席分數):',
-        calculationDescription9:'※可使用excel公式寫!',
-        instantPreview:'算式寫法即時預覽',
-        calculationDescription10:'使用標準化方法將學生的得分轉換為標準分數。',
-        gravityCalculationScore:'比重計算分數',
-        averageScore:'平均分數',
-        standardDeviation:'標準差',
-        standardScoreZFormula:'標準分數(Z)公式:',
-        derivedStandardScoreTFormula:'衍生標準分數(T)公式:',
-        calculationDescription11:'(通常用於解決小數及負數問題)',
-        indicatesAverageScore:'表示平均分數',
-        calculationDescription12:'將學生的得分除以活動的最高分數。然後乘以100,即可計算出學生的百分比評分。',
-        highestScore:'最高分數',
-        calculationDescription13:'請依照下列變數填寫計算公式:',        
-        classQwen:'課堂總數',
-        totalScoreClass:'全班總分',        
-        totalNumberStudents:'學生總數',
-        formulaExample:'公式範例:',
-        writtenas:'寫法為:',
-        scoreboardScore:'記分板成績',          
+    scoreCalc: {
+        creatDate: '建立日期',
+        customInput: '手動輸入',
+        onlineClass: '線上課堂',
+        onlineHomeWork: '線上作業',
+        IRSnumber: 'IRS',
+        addTableInfo: '請先新增成績表',
+        newTable: '新成績統計表',
+        newProject: '新項目',
+        subItem: '子項目',
+        notRated: '未評分',
+        tableIsNaN: '尚無成績表',
+        isNaN: '內容為空',
+        description1: '底線字',
+        description1_2: '可點擊編輯細項',
+        blueWord: '藍字',
+        canModifyable: '可修改',
+        description2: '可修改內容,(括弧)的數字為分數 x 百分比%的結果',
+        simple_complete: '精簡模式/完整模式',
+        title: '標題',
+        name: '姓名',
+        id: '學號',
+        class: '課堂',
+        th_homework: '作業',
+        th_exam: '評量',
+        totalScore: '總評分',
+        PRScore: 'PR值',
+        gradesInClass: '課堂細項成績',
+        attendType: "出席狀態",
+        attend: '出席',//英文版Attendance
+        point: '記分板',
+        interactiveScore: '互動分',
+        attend2: '出席',//英文版Attend
+        leave: '請假',//英文版leave
+        absence: '缺席',//英文版Abs
+        sickLeave: '病假',//英文版SL
+        personalLeave: '事假',//英文版PL
+        publicLeave: '公假',//英文版PH
+        absence2: '缺席',//英文版Absence
+        sickLeave2: '病假',//英文版Sick leave
+        personalLeave2: '事假',//英文版Personal leave
+        publicLeave2: '公假',//英文版Public holiday
+        isSave: '已存檔',
+        notSave: '未存檔',
+        delete: '刪除',
+        export: '匯出',
+        print: '列印',
+        save: '儲存',
+        scoreCalculation: '成績計算',
+        simpleAttendanceCalculation: '簡單出席計算法',
+        attendanceCalculationMethod: '出席率計算法',
+        customCalculation: '自訂計算',
+        percentageScore: '標準化評分',
+        standardizedsScoring: '百分比評分',
+        customScoring: '自訂評分',
+        calculationDescription1: '教師根據學生的出席情況,直接給予分數。通常是以全勤為標準,缺席一次扣一定分數。',
+        calculationDescription2: '請輸入一次缺席扣多少分數',
+        marks: '分',
+        example: '範例:',
+        attendance: '出席成績',
+        fullMarksAttend: '出席滿分',
+        attendPercentage: '出席百分比',
+        absences: '缺席次數',
+        calculationDescription3: '缺席一次扣 ',
+        calculationFormula: '計算公式',
+        calculationDescription4: '勾選即為缺席狀態:',
+        checkOk: '確定',
+        cancel: '取消',
+        calculationDescription5: '根據學生的出席次數計算出席率,再以此作為出席分數的依據。出席率以百分比表示,例如出席率超過90%可得滿分,每低於一個百分點扣一定分數。',
+        calculationDescription6: '每缺席1% 扣',
+        attendanceOver: '出席率超過',
+        isFullMark: '% 為滿分',
+        classGrades: '課堂成績:',
+        totalNumberClasses: '課堂總次數',
+        attendQwen: '出席次數',
+        formula: '公式:',
+        calculationDescription7: '請依照下列變數填寫計算公式:',
+        numberOfSick: '病假次數',
+        numberOfPerson: '事假次數',
+        numberOfPublic: '公假次數',
+        calculationDescription8: '公式範例(以下直接以出席率為出席分數):',
+        calculationDescription9: '※可使用excel公式寫!',
+        instantPreview: '算式寫法即時預覽',
+        calculationDescription10: '使用標準化方法將學生的得分轉換為標準分數。',
+        gravityCalculationScore: '比重計算分數',
+        averageScore: '平均分數',
+        standardDeviation: '標準差',
+        standardScoreZFormula: '標準分數(Z)公式:',
+        derivedStandardScoreTFormula: '衍生標準分數(T)公式:',
+        calculationDescription11: '(通常用於解決小數及負數問題)',
+        indicatesAverageScore: '表示平均分數',
+        calculationDescription12: '將學生的得分除以活動的最高分數。然後乘以100,即可計算出學生的百分比評分。',
+        highestScore: '最高分數',
+        calculationDescription13: '請依照下列變數填寫計算公式:',
+        classQwen: '課堂總數',
+        totalScoreClass: '全班總分',
+        totalNumberStudents: '學生總數',
+        formulaExample: '公式範例:',
+        writtenas: '寫法為:',
+        scoreboardScore: '記分板成績',
         lessonRecordTitle: '課堂紀錄',
         homeworkTitle: '作業活動',
-        examTitle: '評量活動',        
-        totalRate:'總加權',
-        itemName:'項目名稱',
-        percentage:'百分比',
-        tickIncludedScore:'↓勾選則計入成績。 ',
-        dropSort:'※拖曳可排序',
-        itemRate:'比重',
-        logStudentScore:'編輯學生分數',
-        average:'平均',
-        loging:'登錄',
-        score:'成績',
-        attendState:'※出席分數:1出席 2缺席 4病假 5事假 6公假',
-        pasteMultiple:' 多筆貼上',
-        pasteEXCEL:' ※可直接從EXCEL貼上',       
-        back:'返回',        
-        warringTotalRate:'總加權不可超過100%',
-        dataIsSave:'資料已儲存',
-        remind:'提醒',
-        remindMessage1:'有未儲存的設定,要繼續切換活動項目嗎?',
-        remindMessage2:'有未儲存的設定,要繼續新增活動項目嗎?',
-        deleteRemind1:'刪除活動子項目',
-        remindMessage3:'活動子項目數據刪除後將無法找回,確認刪除當前活動子項目嗎?',
-        deleteRemind2:'刪除活動項目',
-        remindMessage4:'活動項目已刪除',
-        remindMessage5:'分數登錄完成',
-        remindMessage6:'有未儲存的設定,確定要繼續嗎?',
-        scoreCalc:'成績計算',        
-        modifyContent:'可修改內容       ',
-        ask:'詢問',
-        DelTableQuestion:'成績表數據刪除後將無法找回,確認刪除此成績表嗎?',
-        saveAsk:'是否確定要儲存此資料表所有內容呢?', 
-        addAsk:'是否確定要新增活動項目呢?',
-        APIerr:'API請求失敗',    
-        AddScoreSheet:'新增成績表',
-        chooseAddWay:'請選擇新增成績表的方式',
-        addNewTable:'新增"新"成績表',
-        InheritTable:'沿用成績表',
-        addTableNotice:'注意:新增的成績表成績以當下系統有的成績為準,成績表成績沒有跟其他功能連動',
+        examTitle: '評量活動',
+        totalRate: '總加權',
+        itemName: '項目名稱',
+        percentage: '百分比',
+        tickIncludedScore: '↓勾選則計入成績。 ',
+        dropSort: '※拖曳可排序',
+        itemRate: '比重',
+        logStudentScore: '編輯學生分數',
+        average: '平均',
+        loging: '登錄',
+        score: '成績',
+        attendState: '※出席分數:1出席 2缺席 4病假 5事假 6公假',
+        pasteMultiple: ' 多筆貼上',
+        pasteEXCEL: ' ※可直接從EXCEL貼上',
+        back: '返回',
+        warringTotalRate: '總加權不可超過100%',
+        dataIsSave: '資料已儲存',
+        remind: '提醒',
+        remindMessage1: '有未儲存的設定,要繼續切換活動項目嗎?',
+        remindMessage2: '有未儲存的設定,要繼續新增活動項目嗎?',
+        deleteRemind1: '刪除活動子項目',
+        remindMessage3: '活動子項目數據刪除後將無法找回,確認刪除當前活動子項目嗎?',
+        deleteRemind2: '刪除活動項目',
+        remindMessage4: '活動項目已刪除',
+        remindMessage5: '分數登錄完成',
+        remindMessage6: '有未儲存的設定,確定要繼續嗎?',
+        scoreCalc: '成績計算',
+        modifyContent: '可修改內容       ',
+        ask: '詢問',
+        DelTableQuestion: '成績表數據刪除後將無法找回,確認刪除此成績表嗎?',
+        saveAsk: '是否確定要儲存此資料表所有內容呢?',
+        addAsk: '是否確定要新增活動項目呢?',
+        APIerr: 'API請求失敗',
+        AddScoreSheet: '新增成績表',
+        chooseAddWay: '請選擇新增成績表的方式',
+        addNewTable: '新增"新"成績表',
+        InheritTable: '沿用成績表',
+        addTableNotice: '注意:新增的成績表成績以當下系統有的成績為準,成績表成績沒有跟其他功能連動',
     },
     activity: {
         scoreWord: {

+ 64 - 104
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperViewBox/LessonTestReport.vue

@@ -111,6 +111,20 @@
                         {{$t("studentWeb.exam.report.noScore")}}: {{rightAns.noAns}}
                     </Checkbox> -->
                 </CheckboxGroup>
+                <Dropdown @on-click="examChange" style="margin-right: 30px;">
+                    <a href="javascript:void(0)">
+                        {{ examType.text }}
+                        <Icon type="ios-arrow-down"></Icon>
+                    </a>
+                    <DropdownMenu slot="list">
+                        <DropdownItem :name="0">
+                            {{ $t('evaluation.paperList.sortByType') }}
+                        </DropdownItem>
+                        <DropdownItem :name="1">
+                            {{ $t('evaluation.paperList.sortByOrder') }}
+                        </DropdownItem>
+                    </DropdownMenu>
+                </Dropdown>
                 <p style="float: right" class="print-hidden">
                     <span style="margin-right: 10px">{{ $t("studentWeb.exam.report.wrongPractice") }}:</span>
                     <Dropdown @on-click="itemChange" style="margin-right: 30px;">
@@ -144,7 +158,7 @@
                     <p class="exam-type" style="margin-bottom: 20px;"
                         v-show="(checkedAns.includes('right') && item.rightNum) || (checkedAns.includes('wrong') && item.wrongNum)"
                     >
-                        <span>{{ $tools.getChineseByNum(index + 1) }}. {{ item.name }}</span>
+                        <span>{{ $tools.getChineseByNum(index + 1) }}. {{ exersicesType[item.type] }}</span>
                         ({{`${$t("studentWeb.exam.info.total1")}${item.exam.length}${$t("studentWeb.exam.info.num")},${$t("studentWeb.exam.info.total2")}${item.score}${$t("studentWeb.exam.score111")}`}})
                     </p>
                     <div v-for="(exam, indexs) in item.exam" :key="indexs" style="display: flex; margin-bottom: 40px;"
@@ -473,7 +487,9 @@
                 testState: 0, //1:未作答  2:未评分  3:已评分
                 paperData: [], //所有题目信息
                 showPaperData: [], //所有题目信息
-                newPaperData: [], //所有题目信息
+                // newPaperData: [], //所有题目信息
+                orderList: [], //题号排序
+                groupList: [], //题型排序
                 ansData: [], //题目的作答答案
                 markData: [], //答案的批注
                 repairData: [],
@@ -481,6 +497,8 @@
                 previewFile: {},
                 numPages: null, //pdf的页数
                 preIndex: null, //点击的题目下标
+                exersicesType: this.$GLOBAL.EXERCISE_TYPES(),
+                typeList: ['single', 'multiple', 'judge', 'complete', 'subjective', 'connector', 'correct', 'compose'],
                 levelList: [ //层次
                     this.$t("evaluation.level1"),
                     this.$t("evaluation.level2"),
@@ -493,6 +511,10 @@
                     name: this.$t("studentWeb.exam.practiceType.onlyWrong"),
                     key: 0,
                 },
+                examType: {
+                    text: '题型排序',
+                    key: 0
+                },
                 quesList: [
                     {
                         name: this.$t("studentWeb.exam.practiceType.onlyWrong"),
@@ -624,92 +646,23 @@
                 }
             },
             async formPaper() {
+                let that = this
                 let paper = []
-                let paperType = [
-                    {
-                        type: "single",
-                        name: this.$t("studentWeb.exam.queType.single"),
-                        exam: [],
-                        score: 0,
-                        rightNum: 0,
-                        wrongNum: 0,
-                    },
-                    {
-                        type: "multiple",
-                        name: this.$t("studentWeb.exam.queType.multiple"),
-                        exam: [],
-                        score: 0,
-                        rightNum: 0,
-                        wrongNum: 0,
-                    },
-                    {
-                        type: "judge",
-                        name: this.$t("studentWeb.exam.queType.judge"),
-                        exam: [],
-                        score: 0,
-                        rightNum: 0,
-                        wrongNum: 0,
-                    },
-                    {
-                        type: "complete",
-                        name: this.$t("studentWeb.exam.queType.complete"),
-                        exam: [],
-                        score: 0,
-                        rightNum: 0,
-                        wrongNum: 0,
-                    },
-                    {
-                        type: "subjective",
-                        name: this.$t("studentWeb.exam.queType.subjective"),
-                        exam: [],
-                        score: 0,
-                        rightNum: 0,
-                        wrongNum: 0,
-                    },
-                    {
-                        type: "connector",
-                        name: this.$t("studentWeb.exam.queType.connector"),
-                        exam: [],
-                        score: 0,
-                        rightNum: 0,
-                        wrongNum: 0,
-                    },
-                    {
-                        type: "correct",
-                        name: this.$t("studentWeb.exam.queType.correct"),
-                        exam: [],
-                        score: 0,
-                        rightNum: 0,
-                        wrongNum: 0,
-                    },
-                    {
-                        type: "compose",
-                        name: this.$t("studentWeb.exam.queType.compose"),
-                        exam: [],
-                        score: 0,
-                        rightNum: 0,
-                        wrongNum: 0,
-                    },
-                ]
                 this.paperData.length = 0
                 this.newPaperData.length = 0
                 this.ansData.length = 0
                 this.markData.length = 0
                 this.quDataSub.length = 0
                 let exam = this.paperInfo.item ? [...this.paperInfo.item] : []
-                if (exam.length) {
+                if(exam.length) {
                     this.ansData = await this.getItem(this.examInfo.stuAns[0])
                     let examNum = 0
                     for (let i = 0; i < exam.length; i++) {
                         if (!exam[i].repair) {
                             exam[i].repair = []
                         }
-                        exam[i].star = false
-                        exam[i].open = false
-                        exam[i].stuAns = []
-                        exam[i].mark = []
-                        exam[i].getScore = 0
-                        exam[i].paperIndex = i + 1
+                        let obj = {star: false, open: false, stuAns: [], mark: [], getScore: 0, paperIndex: i + 1}
+                        Object.assign(exam[i], obj)
                         if (exam[i].type === 'compose') {
                             examNum = !i ? -1 : examNum
                             let k = 1
@@ -721,14 +674,8 @@
                                     if (!exam[i].children[c].repair) {
                                         exam[i].children[c].repair = []
                                     }
-                                    exam[i].children[c].parent = i
-                                    exam[i].children[c].paperIndex = (i + 1) + '-' + k //题号
-                                    exam[i].children[c].stuAns = []
-                                    exam[i].children[c].mark = []
-                                    exam[i].children[c].star = false
-                                    exam[i].children[c].open = false
-                                    exam[i].children[c].getScore = 0
-                                    exam[i].children[c].parentInfo = Object.assign({}, exam[i])
+                                    let objChild = {parent: i, paperIndex: (i + 1) + '-' + k, stuAns: [], mark: [], star: false, open: false, getScore: 0, parentInfo: Object.assign({}, exam[i])}
+                                    Object.assign(exam[i].children[c], objChild)
                                     exam[i].children[c].parentInfo.children = []
                                     exam[i].children[c].stuAns = this.ansData[examNum + c + 1] ? this.ansData[examNum + c + 1] : []
                                     exam[i].children[c].mark = this.examInfo.mark[examNum + c + 1]
@@ -739,7 +686,6 @@
                                     } else {
                                         exam[i].wrongNum += 1
                                     }
-                                    paper.push(exam[i].children[c])
                                     k++
                                 }
                             }
@@ -749,31 +695,39 @@
                             exam[i].stuAns = this.ansData[examNum] ? this.ansData[examNum] : []
                             exam[i].mark = this.examInfo.mark[examNum]
                             exam[i].getScore = this.examInfo.stuScore[examNum]
-                            paper.push(exam[i])
                         }
-                        paperType = paperType.map(item => {
-                            if(item.type === exam[i].type) {
-                                if(exam[i].type === 'compose') {
-                                    item.rightNum += exam[i].rightNum
-                                    item.wrongNum += exam[i].wrongNum
-                                } else {
-                                    if(exam[i].getScore === exam[i].score) {
-                                        item.rightNum += 1
+                        paper.push(exam[i])
+                    }
+                    this.orderList.push({
+                        exam: paper
+                    })
+                    /* 处理试卷内题目按照题型排序 */
+                    this.typeList.forEach(item => {
+                        this._.mapKeys(this._.groupBy(paper, 'type'), function (value, key) {
+                            if (key === item) {
+                                /* 按照题型排序,并且计算每种题型的总分 */
+                                let typeInfo = {
+                                    type: key,
+                                    exam: value,
+                                    score: value.reduce((p, e) => p + e.score, 0),
+                                    rightNum: 0,
+                                    wrongNum: 0,
+                                }
+                                value.forEach(val => {
+                                    if(val.type === 'compose') {
+                                        typeInfo.rightNum += val.rightNum
+                                        typeInfo.wrongNum += val.wrongNum
                                     } else {
-                                        item.wrongNum += 1
+                                        if(val.getScore === val.score) {
+                                            typeInfo.rightNum += 1
+                                        } else {
+                                            typeInfo.wrongNum += 1
+                                        }
                                     }
-                                    
-                                }
-                                item.exam.push(exam[i])
-                                item.score += exam[i].score
+                                })
+                                that.groupList.push(typeInfo)
                             }
-                            return item
                         })
-                    }
-                    paperType.forEach(item => {
-                        if(item.exam.length) {
-                            this.newPaperData.push(item)
-                        }
                     })
                 }
                 if(this.progress === 'finish') {
@@ -927,6 +881,9 @@
             itemChange(item) {
                 this.practiceQuesType = this.quesList[item]
             },
+            examChange(item) {
+                this.examType = item ? {text: this.$t('evaluation.paperList.sortByOrder'), key: 1} : {text: this.$t('evaluation.paperList.sortByType'), key: 0}
+            },
             changeStar(type, typeIndex, parentIndex, exam) {
                 console.log(exam);
                 if(exam.type === 'compose') {
@@ -1077,6 +1034,9 @@
                 // 2024.2.27 青羊区艺术评测结束、结算后不显示统计信息
                 return this.$store.state.userInfo.area === '7a51072f-b329-4e74-99e0-ba0407ba8926' && this.getItemTitle.type === 'Art'
             },
+            newPaperData() {
+                return this.examType.key ? this.orderList : this.groupList
+            },
         },
         watch: {
             examInfo: {

+ 9 - 2
TEAMModelOS/ClientApp/src/components/student-web/WrongQusetion/AnswerBox.less

@@ -191,7 +191,7 @@
         }
 
         .answer-area {
-            display: flex;
+            // display: flex;
             // font-size: 17px;
             margin-bottom: 15px;
 
@@ -199,7 +199,14 @@
             .answer-tip {
                 color: #68A129;
                 margin-right: 10px;
-                min-width: 80px;
+                // min-width: 80px;
+            }
+
+            .answer-info {
+                margin-left: 15px;
+            }
+            .answer-option {
+                display: flex;
             }
         }
 

+ 11 - 7
TEAMModelOS/ClientApp/src/components/student-web/WrongQusetion/AnswerBox.vue

@@ -103,16 +103,20 @@
                     </template>
                     <div v-if="practiceType === 1 || practiceType === 4">
                         <div class="answer-area" v-if="(practiceType === 4)">
-                            <span class="answer-tip">【{{ $t('evaluation.answer') }}】</span>
-                            <p v-for="(answerC, indexCA) in quesInfo.answer" :key="indexCA" v-html="answerC"></p>
+                            <p class="answer-tip">【{{ $t('evaluation.answer') }}】</p>
+                            <div class="answer-info answer-option">
+                                <p v-for="(answerC, indexCA) in quesInfo.answer" :key="indexCA" v-html="answerC"></p>
+                            </div>
                         </div>
                         <div class="answer-area">
-                            <span class="answer-tip">【{{ $t('evaluation.explain') }}】</span>
-                            <p v-html="quesInfo.explain"></p>
+                            <p class="answer-tip">【{{ $t('evaluation.explain') }}】</p>
+                            <div class="answer-info">
+                                <p v-html="quesInfo.explain"></p>
+                            </div>
                         </div>
                         <div class="answer-area" v-if="quesInfo.repair">
-                            <span class="answer-tip">【{{ $t('evaluation.newExercise.repair') }}】</span>
-                            <div v-if="quesInfo.repair.length != 0">
+                            <p class="answer-tip">【{{ $t('evaluation.newExercise.repair') }}】</p>
+                            <div v-if="quesInfo.repair.length != 0" class="answer-info">
                                 <div v-for="(repairSource, normalIndex) in quesInfo.repair" :key="normalIndex" class="repair-link-wrap-item-box">
                                     <div class="file-icon">
                                         <img :src="$tools.getFileThum(repairSource.type, repairSource.name)"/>
@@ -126,7 +130,7 @@
                                     </div>
                                 </div>
                             </div>
-                            <div v-else-if="!quesInfo.repair.length">
+                            <div v-else-if="!quesInfo.repair.length" class="answer-info">
                                 {{ $t('studentWeb.exam.report.noSource') }}
                             </div>
                         </div>

+ 10 - 0
TEAMModelOS/ClientApp/src/utils/evTools.js

@@ -46,6 +46,8 @@ export default {
 					explain: item.explain,
 					type: item.type,
 					answerType: item.answerType || 'text',
+					useAutoScore: item.useAutoScore || false,
+					answerLang: item.answerLang || 'en-US',
 					objective: this.getItemType(item.type),
 					opts: item.option ? item.option.length : 0,
 					knowledge: item.knowledge,
@@ -86,6 +88,8 @@ export default {
 				type: item.type,
 				answer: item.answer || [],
 				answerType: item.answerType || 'text',
+				useAutoScore: item.useAutoScore || false,
+				answerLang: item.answerLang || 'en-US',
 				objective: this.getItemType(item.type),
 				question: this.getSimpleText(item.question),
 				knowledge: item.knowledge,
@@ -177,6 +181,8 @@ export default {
 			jsonData.exercise.code = tmdId
 			jsonData.exercise.option = jsonData.item[0].option
 			jsonData.exercise.answerType = jsonData.item[0].answerType || 'text'
+			jsonData.exercise.useAutoScore = jsonData.item[0].useAutoScore || false
+			jsonData.exercise.answerLang = jsonData.item[0].answerLang || 'en-US'
 			jsonData.exercise.id = jsonData.id
 			jsonData.exercise.scope = 'private'
 			jsonData.exercise.pid = jsonData.pid
@@ -259,6 +265,8 @@ export default {
 							jsonData.id = list[i].id
 							jsonData.exercise.question = jsonData.item[0].question
 							jsonData.exercise.answerType = jsonData.item[0].answerType || 'text'
+							jsonData.exercise.useAutoScore = jsonData.item[0].useAutoScore || false
+							jsonData.exercise.answerLang = jsonData.item[0].answerLang || 'en-US'
 							jsonData.exercise.createTime = list[i].createTime || 0
 							jsonData.exercise.blob = list[i].blob
 							jsonData.exercise.code = list[i].code
@@ -432,6 +440,8 @@ export default {
 						// 调整渲染试题数据结构
 						jsonData.exercise.question = jsonData.item[0].question
 						jsonData.exercise.answerType = jsonData.item[0].answerType || 'text'
+						jsonData.exercise.useAutoScore = jsonData.item[0].useAutoScore || false
+						jsonData.exercise.answerLang = jsonData.item[0].answerLang || 'en-US'
 						jsonData.exercise.blob = url
 						jsonData.exercise.code = code
 						jsonData.exercise.option = jsonData.item[0].option

+ 3 - 0
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseEditExercise.vue

@@ -297,6 +297,9 @@ export default {
           break;
         case "subjective":
           exerciseItem.question = this.$refs.subjective.stemContent;
+           exerciseItem.answerType = this.$refs.subjective.answerType; // 02040301 问答题增加作答类型字段
+          exerciseItem.useAutoScore = this.$refs.subjective.useAutoScore; // 02040301 问答题增加作答类型字段
+          exerciseItem.answerLang = this.$refs.subjective.answerLang; // 02040301 问答题增加作答类型字段
           exerciseItem.option = [];
           exerciseItem.type = this.exersicesType;
           exerciseItem.level = +this.exersicesDiff;

+ 5 - 1
TEAMModelOS/ClientApp/src/view/evaluation/index/CreateExercises.vue

@@ -174,7 +174,9 @@ const defaultExercise = {
   answer: [],
   explain: "",
   type: "",
-  answerType:'text'
+  answerType:'text',
+  useAutoScore: false,
+	answerLang: "en-US",
 };
 export default {
   components: {
@@ -357,6 +359,8 @@ export default {
           exerciseItem.level = +this.exersicesDiff;
           exerciseItem.explain = this.analysisContent;
           exerciseItem.answerType = this.$refs.subjective.answerType; // 02040301 问答题增加作答类型字段
+          exerciseItem.useAutoScore = this.$refs.subjective.useAutoScore; // 02040301 问答题增加作答类型字段
+          exerciseItem.answerLang = this.$refs.subjective.answerLang; // 02040301 问答题增加作答类型字段
           exerciseItem.answer = [this.$refs.subjective.answerContent];
           break;
         case "connector":

+ 22 - 8
TEAMModelOS/ClientApp/src/view/evaluation/types/BaseSubjective.vue

@@ -9,11 +9,23 @@
 		<div class="exersices-content answer-type">
 			<IconText :text="$t('evaluation.newExercise.answerType.types')" :color="'#07ac88'" :icon="'md-chatbubbles'"></IconText>
 			<div class="types">
-				<span :class="['type-item', answerType === 'text' ? 'type-item-active' : '']" @click="answerType = 'text'">{{ $t('evaluation.newExercise.answerType.text') }}</span>
-				<span :class="['type-item', answerType === 'text_Image' ? 'type-item-active' : '']" @click="answerType = 'text_Image'">{{ $t('evaluation.newExercise.answerType.textImage') }}</span>
-				<span :class="['type-item', answerType === 'Image' ? 'type-item-active' : '']" @click="answerType = 'Image'">{{ $t('evaluation.newExercise.answerType.image') }}</span>
-				<span :class="['type-item', answerType === 'file' ? 'type-item-active' : '']" @click="answerType = 'file'">{{ $t('evaluation.newExercise.answerType.file') }}</span>
-				<span :class="['type-item', answerType === 'audio' ? 'type-item-active' : '']" @click="answerType = 'audio'">{{ $t('evaluation.newExercise.answerType.audio') }}</span>
+				<span :class="['type-item', answerType === 'text' ? 'type-item-active' : '']" @click="answerType = 'text'">{{ $t("evaluation.newExercise.answerType.text") }}</span>
+				<span :class="['type-item', answerType === 'text_Image' ? 'type-item-active' : '']" @click="answerType = 'text_Image'">{{ $t("evaluation.newExercise.answerType.textImage") }}</span>
+				<span :class="['type-item', answerType === 'Image' ? 'type-item-active' : '']" @click="answerType = 'Image'">{{ $t("evaluation.newExercise.answerType.image") }}</span>
+				<span :class="['type-item', answerType === 'file' ? 'type-item-active' : '']" @click="answerType = 'file'">{{ $t("evaluation.newExercise.answerType.file") }}</span>
+				<span :class="['type-item', answerType === 'audio' ? 'type-item-active' : '']" @click="answerType = 'audio'">{{ $t("evaluation.newExercise.answerType.audio") }}</span>
+				<div style="display: inline-block;" v-if="answerType === 'audio'"> 
+					<span style="margin-right: 10px">{{ $t("evaluation.newExercise.answerType.autoScore") }}</span>
+					<i-switch v-model="useAutoScore" />
+					<span style="margin: 10px 20px">{{ $t("evaluation.newExercise.answerType.answerLang") }}</span>
+					<Select v-model="answerLang" style="width: 150px">
+						<Option value="en-US">{{ $t("evaluation.newExercise.answerType.us") }}(en-US)</Option>
+						<Option value="zh">{{ $t("evaluation.newExercise.answerType.zh") }}(zh) </Option>
+						<Option value="ja-JP">{{ $t("evaluation.newExercise.answerType.jp") }}(ja-JP)</Option>
+						<Option value="ko-KR">{{ $t("evaluation.newExercise.answerType.kr") }}(ko-KR)</Option>
+						<Option value="zh-HK">{{ $t("evaluation.newExercise.answerType.hk") }}(zh-HK)</Option>
+					</Select>
+				</div>
 			</div>
 		</div>
 		<div class="exersices-option">
@@ -44,6 +56,8 @@
 		data() {
 			return {
 				answerType: "text",
+				useAutoScore: false,
+				answerLang: "en-US",
 				stemContent: "",
 				stemEditor: null,
 				answerContent: "",
@@ -54,7 +68,7 @@
 			doRender() {
 				this.stemContent = this.editInfo.question;
 				this.answerContent = this.editInfo.answer[0];
-				this.answerType = this.editInfo.answerType || 'text'
+				this.answerType = this.editInfo.answerType || "text";
 				this.stemEditor.txt.html(this.editInfo.question);
 				this.answerEditor.txt.html(this.editInfo.answer[0]);
 			}
@@ -110,8 +124,8 @@
 			margin-top: 20px;
 			border: 1px solid #dddddd;
 			cursor: pointer;
-			&-active{
-				background: #10ABE7;
+			&-active {
+				background: #10abe7;
 				color: #fff;
 			}
 		}

+ 6 - 0
TEAMModelOS/ClientApp/src/view/mycourse/MyCourse.vue

@@ -884,6 +884,9 @@
 				} else if (!this.listId && this.type == "select") {
 					return this.$Message.warning(this.$t("cusMgt.selectListTips"));
 				}
+				if(this.listName && this.type == "create" && this.teaClassList.find(item => item.name === this.listName)) {
+					return this.$Message.warning(this.$t("cusMgt.renameRepeat"));
+				}
 				if (this.type == "create") {
 					let stuList = {
 						code: this.$store.state.userInfo.TEAMModelId,
@@ -1067,6 +1070,9 @@
 				this.editClassStatus = true;
 			},
 			confirmRename() {
+				if(this.edName && this.teaClassList.find(item => item.name === this.edName)) {
+					return this.$Message.warning(this.$t("cusMgt.renameRepeat"));
+				}
 				let stulistId = this.teaClassList[this.curClassIndex].groupId;
 				let stulist = this.courseGroupList.find((item) => {
 					return item.id == this.teaClassList[this.curClassIndex].groupId;

+ 0 - 1
TEAMModelOS/Controllers/Analysis/ChangeController.cs

@@ -11,7 +11,6 @@ using System.Threading.Tasks;
 using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 using TEAMModelOS.SDK.Helper.Common.JsonHelper;
 using TEAMModelOS.SDK.Helper.Common.JsonHelper.JsonPath;
 using TEAMModelOS.SDK.Helper.Security.ShaHash;

+ 0 - 1
TEAMModelOS/Controllers/Analysis/ClassAnalysisController.cs

@@ -26,7 +26,6 @@ using TEAMModelOS.Models;
 using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
 using System.Net;

+ 3 - 3
TEAMModelOS/Controllers/Both/CourseController.cs

@@ -703,7 +703,7 @@ namespace TEAMModelOS.Controllers
 
                 try
                 {
-                    await GroupListService.DeleteGrouplistEvent($"{stulist}", "GroupList", Constant.Teacher, client, _configuration, _serviceBus);
+                    await GroupListService.DeleteGrouplistEvent($"{stulist}", "GroupList", Constant.Teacher, client, _configuration, _serviceBus,"web");
                 }
                 catch (Exception ex) {  }
                
@@ -910,7 +910,7 @@ namespace TEAMModelOS.Controllers
                         foreach (var listid in courseChange.delList) {
                             try
                             {
-                                await GroupListService.DeleteGrouplistEvent(listid, "GroupList", Constant.Teacher, client, _configuration, _serviceBus);
+                                await GroupListService.DeleteGrouplistEvent(listid, "GroupList", Constant.Teacher, client, _configuration, _serviceBus, "web");
                             }
                             catch (Exception ex) { continue; }
                         }
@@ -921,7 +921,7 @@ namespace TEAMModelOS.Controllers
                         if (exlists.Any()) {
                             foreach (var listid in exlists) {
                                 try {
-                                    await  GroupListService.DeleteGrouplistEvent(listid, "GroupList", Constant.Teacher, client, _configuration, _serviceBus);
+                                    await  GroupListService.DeleteGrouplistEvent(listid, "GroupList", Constant.Teacher, client, _configuration, _serviceBus, "web");
                                 } catch (Exception ex) { continue; }
                             }
                         }

+ 13 - 13
TEAMModelOS/Controllers/Both/GroupListController.cs

@@ -179,11 +179,11 @@ namespace TEAMModelOS.Controllers
                 }
             }
             int year = DateTimeOffset.UtcNow.Year;
-            (int status, GroupList stuList, Member member) data = await GroupListService.CodeJoinList(client, _azureRedis, $"{_stuListNo}", id, type: 1, $"{school}", year, $"{name}", $"{picture}", $"{lang}", seatNo, $"{_courseId}");
+            (int status, GroupList stuList, Member member) data = await GroupListService.CodeJoinList(client, _azureRedis, $"{_stuListNo}", id, type: 1, $"{school}", year, $"{name}", $"{picture}", $"{lang}", seatNo, $"{_courseId}","hita");
             //没有TmdUser时
             if (data.status == 0)
             {
-                await GroupListService.UpsertList(data.stuList, _azureCosmos, _configuration, _serviceBus);
+                await GroupListService.UpsertList(data.stuList, _azureCosmos, _configuration, _serviceBus,_client: "hita");
 
                 List<string> ids = new List<string>();
                 if (data.stuList.scope.Equals("private") && !string.IsNullOrEmpty(data.stuList.creatorId))
@@ -263,11 +263,11 @@ namespace TEAMModelOS.Controllers
                 type = 1;
             }
             int seatNo =0;
-            (int status, GroupList stuList, Member member) data = await GroupListService.CodeJoinList(client, _azureRedis, $"{_stuListNo}", userid, type, school, year, _name, _picture, head_lang,seatNo);
+            (int status, GroupList stuList, Member member) data = await GroupListService.CodeJoinList(client, _azureRedis, $"{_stuListNo}", userid, type, school, year, _name, _picture, head_lang,seatNo,_client:"web");
             if (data.status == 0)
             {
 
-                await GroupListService.UpsertList(data.stuList, _azureCosmos, _configuration, _serviceBus);
+                await GroupListService.UpsertList(data.stuList, _azureCosmos, _configuration, _serviceBus, "web");
 
                 List<string> ids = new List<string>();
                 if (data.stuList.scope.Equals("private") && !string.IsNullOrEmpty(data.stuList.creatorId))
@@ -1393,7 +1393,7 @@ namespace TEAMModelOS.Controllers
                                     {
                                         foreach (var t in takes)
                                         {
-                                            GroupListService.JoinList(list, t.userid, t.type, t.school, t.year,t.seatNo);
+                                           await GroupListService.JoinList(_azureRedis, list, t.userid, t.type, t.school, t.year,t.seatNo, _client: "web");
                                             string stuKey = !string.IsNullOrWhiteSpace(school) ? $"GroupList:StudentWaitinglist:{school}_{t.userid}" : $"GroupList:StudentWaitinglist:{t.userid}";
                                             string stuFiled = $"{list.scope}:{list.id}";
                                             var data = await _azureRedis.GetRedisClient(8).HashGetAsync(stuKey, stuFiled);
@@ -1455,31 +1455,31 @@ namespace TEAMModelOS.Controllers
                     case bool when $"{list.type}".Equals("teach", StringComparison.OrdinalIgnoreCase):
                         list.type = "teach";
                         list = await GroupListService.CheckListNo(list, _azureCosmos, _dingDing, _option);
-                        list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus);
+                        list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus, "web");
                         break;
                     //教研组名单,只有加入学校的老师名单 成员账号类型是醍摩豆ID,保存在学校表,分区键为GroupList-hbcn
                     case bool when $"{list.type}".Equals("research", StringComparison.OrdinalIgnoreCase):
                         list.type = "research";
                         list.scope = "school";
-                        list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus);
+                        list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus, "web");
                         break;
                     //个人好友名单,成员账号类型可以是学校学生账号和醍摩豆ID,分区键为GroupList
                     case bool when $"{list.type}".Equals("friend", StringComparison.OrdinalIgnoreCase):
                         list.type = "friend";
                         list.scope = "private";
-                        list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus);
+                        list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus, "web");
                         break;
                     //社交群组类型(包含学校交流群组,个人交流群组),成员账号类型可以是学校学生账号和醍摩豆ID,,分区键为GroupList-hbcn 
                     case bool when $"{list.type}".Equals("group", StringComparison.OrdinalIgnoreCase):
                         list.type = "group";
                         list = await GroupListService.CheckListNo(list, _azureCosmos, _dingDing, _option);
-                        list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus);
+                        list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus , "web");
                         break;
                     //研修类型成员账号类型可以是学校学生账号和醍摩豆ID,,分区键为GroupList-hbcn 
                     case bool when $"{list.type}".Equals("yxtrain", StringComparison.OrdinalIgnoreCase):
                         list.type = "yxtrain";
                         list.scope = "school";
-                        list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus);
+                        list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus, "web");
                         break;
                     default:
                         return Ok(new { error = 400, msg = "参数错误!" });
@@ -1521,7 +1521,7 @@ namespace TEAMModelOS.Controllers
                 }
                 try
                 {
-                    await GroupListService.DeleteGrouplistEvent($"{id}", datacode, tbname, client, _configuration, _serviceBus);
+                    await GroupListService.DeleteGrouplistEvent($"{id}", datacode, tbname, client, _configuration, _serviceBus, "web");
                 }
                 catch (Exception ex) { }
                 return Ok(new { id });
@@ -1686,7 +1686,7 @@ namespace TEAMModelOS.Controllers
                                                     var mb = groupList.members.Find(x => x.type==value.type  && x.id.Equals(value.userid));
                                                     if (mb== null)
                                                     {
-                                                        var joindata = GroupListService.JoinList(groupList, value.userid, value.type, value.school, value.year);
+                                                        var joindata =await GroupListService.JoinList( _azureRedis,groupList, value.userid, value.type, value.school, value.year, _client: "hita");
                                                         if (joindata.status==0) {
                                                             add=true;
                                                         }
@@ -1715,7 +1715,7 @@ namespace TEAMModelOS.Controllers
                                 }
                                 if (add)
                                 {
-                                    await GroupListService.UpsertList(groupList, _azureCosmos, _configuration, _serviceBus);
+                                    await GroupListService.UpsertList(groupList, _azureCosmos, _configuration, _serviceBus, _client: "hita");
                                 }
                             }
                         }

+ 0 - 1
TEAMModelOS/Controllers/Both/ScoreCalcController.cs

@@ -54,7 +54,6 @@ using TEAMModelOS.Models.Dto;
 using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
 using TEAMModelOS.SDK.Models.Cosmos.OpenEntity;

+ 2 - 1
TEAMModelOS/Controllers/Client/HiTAControlller.cs

@@ -241,6 +241,7 @@ namespace TEAMModelOS.Controllers.Client
                 auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id_token.Payload.Sub, $"{name}",$"{picture}", _option.JwtSecretKey, Website: "IES", scope: Constant.ScopeTeacher, schoolID: join.school, areaId: school.areaId, standard: school.standard, roles: schoolTeacher.roles.ToArray(), permissions:schoolTeacher.permissions.ToArray(), expire: 1);
 
             }
+            await SystemService.RecordAccumulateData(_azureRedis, _dingDing, new SDK.Models.Dtos.Accumulate { client="hita", count=1, id=school.id, key="teacher_login", name="醍摩豆账号登录", scope="school", target=school.id });
             return Ok(new { periodSubjects,auth_token });
         }
 
@@ -606,7 +607,7 @@ namespace TEAMModelOS.Controllers.Client
                         _ = _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 });
                 }
                 else //無此老師

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

@@ -32,7 +32,6 @@ using TEAMModelOS.Models.Request;
 using Azure;
 using TEAMModelOS.Controllers.Both;
 using TEAMModelOS.SDK.Models.Cosmos.School;
-using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 using Azure.Storage.Blobs;
 
 
@@ -725,7 +724,7 @@ namespace TEAMModelOS.Controllers.Client
 
 
                 list = await GroupListService.CheckListNo(list, _azureCosmos, _dingDing, _option);
-                list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus);
+                list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus, _client: "hita");
 
                 #region === 更新DB課程名單 ===
                 //if (!request.TryGetProperty("datas", out JsonElement _datas))
@@ -1887,7 +1886,7 @@ namespace TEAMModelOS.Controllers.Client
                 var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete);
                 var (blob_uri_read, blob_sas_read) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Read);
                 var (blob_uri_write, blob_sas_write) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write);
-
+                await SystemService.RecordAccumulateData(_azureRedis, _dingDing, new SDK.Models.Dtos.Accumulate { client="hiteach", count=1, id="ies", key="tmd_login", name="醍摩豆账号登录", scope="ies", target="ies" });
                 return Ok(new { blob_uri, blob_sas, blob_sas_read, blob_sas_write, schools, defaultschool, courses, exams });
 
             }
@@ -2461,6 +2460,7 @@ namespace TEAMModelOS.Controllers.Client
                 var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Write); //讀列
                 var (blob_uri_read, blob_sas_read) = _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Read); //讀
                 var (blob_uri_write, blob_sas_write) = _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Write); //寫 
+                await SystemService.RecordAccumulateData(_azureRedis, _dingDing, new SDK.Models.Dtos.Accumulate { client="hiteach", count=1, id=school_base.id, key="teacher_login", name="醍摩豆账号登录", scope="school", target=school_base.id });
                 return Ok(new { blob_uri, blob_sas, blob_sas_read, blob_sas_write, periods, grades, subjects, courses, examTypes, exams });
             }
             catch (Exception ex)

+ 2 - 1
TEAMModelOS/Controllers/Client/HiTeachccControlller.cs

@@ -22,6 +22,7 @@ using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Models.Service;
 using TEAMModelOS.SDK.Services;
 
 namespace TEAMModelOS.Controllers.Client
@@ -365,7 +366,7 @@ namespace TEAMModelOS.Controllers.Client
                 await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在
                 var (blob_uri, blob_sas_read) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Read);
                 var (blob_uri_write, blob_sas_write) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write);
-
+                await SystemService.RecordAccumulateData(_azureRedis, _dingDing, new SDK.Models.Dtos.Accumulate { client="hiteachcc", count=1, id="ies", key="tmd_login", name="醍摩豆账号登录", scope="ies", target="ies" });
                 return Ok(new { blob_uri, blob_sas_read, blob_sas_write });
             }
             catch (Exception ex)

+ 1 - 1
TEAMModelOS/Controllers/Common/AreaController.cs

@@ -286,7 +286,7 @@ namespace TEAMModelOS.Controllers
                 list.name = areaStudy.name;
                 list.school = null;
                 list = await GroupListService.CheckListNo(list, _azureCosmos, _dingDing, _option);
-                list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus);
+                list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus, _client: "web");
                 areaStudy.tchLists.Add(list.id);
                 foreach (string scId in baseIds)
                 {

+ 0 - 1
TEAMModelOS/Controllers/Common/ExamController.cs

@@ -38,7 +38,6 @@ using TEAMModelOS.SDK.Models.Cosmos.Student;
 using DocumentFormat.OpenXml.Drawing.Charts;
 using ClouDASLibx;
 using HTEXLib.Helpers.ShapeHelpers;
-using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 using Microsoft.Extensions.Hosting;
 using System.Configuration;
 using DocumentFormat.OpenXml.Presentation;

+ 1 - 1
TEAMModelOS/Controllers/Common/StudyController.cs

@@ -114,7 +114,7 @@ namespace TEAMModelOS.Controllers.Common
                                     member.code = study.school;
                                     group.members.Add(member);
                                 }
-                                await GroupListService.UpsertList(group, _azureCosmos, _configuration, _serviceBus);
+                                await GroupListService.UpsertList(group, _azureCosmos, _configuration, _serviceBus, _client: "web");
                                 // await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync(group, group.id, new PartitionKey($"{group.code}"));
                             }
                         }

+ 6 - 6
TEAMModelOS/Controllers/OpenApi/OpenSchool/ScGroupListController.cs

@@ -336,7 +336,7 @@ namespace TEAMModelOS.Controllers
                         if (infos.Any())
                         {
                             int year = DateTimeOffset.UtcNow.Year;
-                            infos.ToList().ForEach(x =>
+                            infos.ToList().ForEach(async x =>
                             {
                                 var mebJoined = list.members.Find(m => m.id.Equals(x.id) && m.type == 1);
                                 var mb = tmds.Where(m => m.id.Equals(x.id) && m.type == 1).First();
@@ -365,7 +365,7 @@ namespace TEAMModelOS.Controllers
                                 }
                                 else
                                 {
-                                    (int status, GroupList stuList, Member member) = GroupListService.JoinList(list, x.id, 1, school,year);
+                                    (int status, GroupList stuList, Member member) =await GroupListService.JoinList(_azureRedis, list, x.id, 1, school,year, _client: "web");
                                     member.nickname = mb.nickname == null ? mebJoined.nickname : mb.nickname;
                                     member.groupName = groupName == null ? member.groupName : groupName;
                                     member.groupId = groupId == null ? member.groupId : groupId;
@@ -374,7 +374,7 @@ namespace TEAMModelOS.Controllers
                         }
                         if (stus.Any())
                         {
-                            stus.ToList().ForEach(x =>
+                            stus.ToList().ForEach(async x =>
                             {
                                 var mebJoined = list.members.Find(m => m.id.Equals(x.id) && m.type == 2);
                                 var mb = stus.Where(m => m.id.Equals(x.id) && m.type == 2).First();
@@ -402,7 +402,7 @@ namespace TEAMModelOS.Controllers
                                 }
                                 else
                                 {
-                                    (int status, GroupList stuList, Member member) = GroupListService.JoinList(list, x.id, 2, school,x.year);
+                                    (int status, GroupList stuList, Member member) =await GroupListService.JoinList( _azureRedis,list, x.id, 2, school,x.year, _client:"web");
                                     member.nickname = mb.nickname == null ? mebJoined.nickname : mb.nickname;
                                     member.groupName = groupName == null ? member.groupName : groupName;
                                     member.groupId = groupId == null ? member.groupId : groupId;
@@ -411,7 +411,7 @@ namespace TEAMModelOS.Controllers
                         }
 
                         list = await GroupListService.CheckListNo(list, _azureCosmos, _dingDing, _option);
-                        list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus);
+                        list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus, _client: "web");
                         return Ok(new
                         {
                             unexist_student,
@@ -503,7 +503,7 @@ namespace TEAMModelOS.Controllers
                             }
                         });
                     }
-                    list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus);
+                    list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus, _client: "web");
                     return Ok(new
                     {
                         remove_stuids,

+ 1 - 1
TEAMModelOS/Controllers/School/ClassController.cs

@@ -270,7 +270,7 @@ namespace TEAMModelOS.Controllers
                 {
                     tasks.Add(client.GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync(stu, stu.id, new PartitionKey(($"Base-{code}"))));
                 }
-                GroupChange change = new GroupChange();
+                GroupChange change = new GroupChange() { client="web",name =clssz .name};
                 if (students.IsNotEmpty()) {
                     change.stuleave.AddRange(students.Select(x=> new Member {
                         id = x.id,

+ 1 - 1
TEAMModelOS/Controllers/School/SchoolTeacherController.cs

@@ -1085,7 +1085,7 @@ namespace TEAMModelOS.Controllers
                         if (exists)
                         {
                             item.members.RemoveAll(x => x.id.Equals(id.ToString()));
-                            await GroupListService.UpsertList(item, _azureCosmos, _configuration, _azureServiceBus);
+                            await GroupListService.UpsertList(item, _azureCosmos, _configuration, _azureServiceBus, _client: "web");
                             //await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(item,item.id,new PartitionKey(item.code));
                         }
                     }

+ 3 - 0
TEAMModelOS/Controllers/Student/StudentController.cs

@@ -142,8 +142,11 @@ namespace TEAMModelOS.Controllers
                                 }
                                 else
                                 {
+                                    Class clazz =await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<Class>(classId, new PartitionKey($"Class-{schoolId}"));
                                     GroupChange change = new GroupChange
                                     {
+                                        client="web",
+                                        name=clazz.name,
                                         scope = "school",
                                         school = schoolId.GetString(),
                                         type = "student",

+ 2 - 2
TEAMModelOS/Controllers/System/CoreController.cs

@@ -726,8 +726,8 @@ namespace TEAMModelOS.Controllers
                 os = "OSX";
             } 
             string region = await _searcher.SearchIpAsync(ip);
-
-            return Ok(new { os, version, description, nowtime, region, ip });
+            TimeZoneInfo localTimezone = TimeZoneInfo.Local; // 获取本地时区信息
+            return Ok(new { os, version, description, nowtime, region, ip, localTimezone , Hours = localTimezone.BaseUtcOffset.Hours, ticks=localTimezone.BaseUtcOffset.Ticks, utcNowoff =  DateTimeOffset.UtcNow, nowoff = DateTimeOffset.Now,utcNow =DateTime.UtcNow,now =DateTime.Now });
         }
         /// <summary>
         /// 等待P1V3,啟動Dcoker,支持EMF GDI+

+ 2 - 1
TEAMModelOS/Controllers/Teacher/InitController.cs

@@ -538,6 +538,7 @@ namespace TEAMModelOS.Controllers
                 //返回剩余空间
                 (long usedSize, long teach, long total, long surplus, Dictionary<string, double?> catalog) space =
                     await BlobService.GetSurplusSpace(teacherInfo.teacher.id, "private", _option.Location, _azureCosmos, _azureRedis, _azureStorage, _dingDing, _httpTrigger);
+                await SystemService.RecordAccumulateData(_azureRedis, _dingDing, new SDK.Models.Dtos.Accumulate {  client="web", count=1, id="ies", key="tmd_login", name="醍摩豆账号登录", scope="ies", target="ies"});
                 if (string.IsNullOrWhiteSpace(lang))
                 {
                     if (_option.Location.Contains("China"))
@@ -960,7 +961,7 @@ namespace TEAMModelOS.Controllers
                 //返回剩余空间
                 (long usedSize, long teach, long total, long surplus, Dictionary<string, double?> catalog) space =
                     await BlobService.GetSurplusSpace(school_base.id, "school", _option.Location, _azureCosmos, _azureRedis, _azureStorage, _dingDing, _httpTrigger);
-
+                await SystemService.RecordAccumulateData(_azureRedis, _dingDing, new SDK.Models.Dtos.Accumulate { client="web", count=1, id=school_code, key="teacher_login", name="醍摩豆账号登录", scope="school", target=school_code});
                 return Ok(new
                 {
                     privateShows = shows?.FindAll(x => x.Scope.Equals("private")).Select(x => new { x.Type, x.Status, x.Scope, x.Code }),

+ 2 - 2
TEAMModelOS/Controllers/Third/Sc/ScController.cs

@@ -194,7 +194,7 @@ namespace TEAMModelOS.Controllers
                                     if (meber == null || meber.Count() <= 0)
                                     {
                                         yxtrain[0].members.Add(new Member { id = teacher.id, type = 1 });
-                                        await GroupListService.UpsertList(yxtrain[0], _azureCosmos, _configuration, _serviceBus);
+                                        await GroupListService.UpsertList(yxtrain[0], _azureCosmos, _configuration, _serviceBus, _client: "web");
                                     }
                                 }
                                 else
@@ -214,7 +214,7 @@ namespace TEAMModelOS.Controllers
                                         ttl = -1,
                                         expire=0,
                                     };
-                                    await GroupListService.UpsertList(groupList, _azureCosmos, _configuration, _serviceBus);
+                                    await GroupListService.UpsertList(groupList, _azureCosmos, _configuration, _serviceBus, _client: "web");
                                 }
                             }
                             Azure.Response response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(teacher.id, new PartitionKey($"Teacher-{school.schoolId}"));

+ 9 - 22
TEAMModelOS/Controllers/XTest/FixDataController.cs

@@ -95,26 +95,13 @@ namespace TEAMModelOS.Controllers
         [HttpPost("fix-debate")]
         public async Task<IActionResult> FixElegant(JsonElement json)
         {
-            string sqlE = $"select value c from c where c.pk='Debate'  ";
-            var resultE = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<Debate>(sqlE);
-            if (resultE .list.IsNotEmpty()) {
-                foreach (var item in resultE.list) 
-                {
-                    item.scope="school";
-                }
-                var group = resultE.list.Where(x => !string.IsNullOrWhiteSpace(x.school)).GroupBy(x => x.school).Select(x => new { key = x.Key, list = x.ToList() });
-                foreach (var gp in group) {
-                    List<Task<ItemResponse<Debate>>> tasks = new List<Task<ItemResponse<Debate>>>();
-                    try
-                    {
-                        foreach (var item in gp.list)
-                        {
-                           await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).UpsertItemAsync(item);
-                        }
-                    }
-                    catch (Exception ex) {
-                       await _dingDing.SendBotMsg($"{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
-                    }
+            string sql = "select value c from c where c.code='Base-zjaz' and c.graduate=1";
+            var result =  await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<Student>(sql, "Base-zjaz");
+            if (result.list.IsNotEmpty()) 
+            {
+                foreach (var item in result.list) {
+                    item.graduate=0;
+                    await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).UpsertItemAsync(item, new PartitionKey(item.code));
                 }
             }
             return Ok();
@@ -1167,7 +1154,7 @@ namespace TEAMModelOS.Controllers
                             {
                                 groupList.members.Add(new Member { id = schjoin.tmdid, type = 1 });
                             }
-                            await GroupListService.UpsertList(groupList, _azureCosmos, _configuration, _serviceBus);
+                            await GroupListService.UpsertList(groupList, _azureCosmos, _configuration, _serviceBus, _client: "web");
                         }
                     }
                     else
@@ -1196,7 +1183,7 @@ namespace TEAMModelOS.Controllers
                                 pk = "GroupList",
                                 ttl = -1
                             };
-                            await GroupListService.UpsertList(groupList, _azureCosmos, _configuration, _serviceBus);
+                            await GroupListService.UpsertList(groupList, _azureCosmos, _configuration, _serviceBus, _client: "web");
                         }
                     }
                     var schtch = joins.FindAll(x => x.schoolId.Equals(sch.id));

+ 4 - 37
TEAMModelOS/Controllers/XTest/TestController.cs

@@ -54,12 +54,12 @@ using TEAMModelOS.Models;
 using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
-using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 using TEAMModelOS.SDK.Helper.Common.JsonHelper.JsonPath;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
 using TEAMModelOS.SDK.Models.Cosmos.OpenEntity;
 using TEAMModelOS.SDK.Models.Cosmos.School;
+using TEAMModelOS.SDK.Models.Dtos;
 using TEAMModelOS.SDK.Models.Service;
 using TEAMModelOS.SDK.Models.Service.BI;
 using TEAMModelOS.SDK.Services;
@@ -115,46 +115,13 @@ namespace TEAMModelOS.Controllers
         /// <param name="file"></param>
         /// <param name="periodId"></param>
         /// <returns></returns>
-        [HttpPost("remove-stucourse")]
+        [HttpPost("test-accumulate")]
         [RequestSizeLimit(102_400_000_00)] //最大10000m左右
         public async Task<IActionResult> RemoveStuCourse(JsonElement json)
         {
 
-            JsonNode jsonNode = JsonObject.Parse(json.ToString());
-            var path= JsonPath.Parse("$.groupLists[*].groupList.members[*]");
-            var d = path.Evaluate(jsonNode);
-            JsonPathContext context = new JsonPathContext
-            { ValueSystem = new JsonApiValueSystem() };
-            //解析试卷作答详情
-            var datas = context.SelectNodes(json,
-            "$.groupLists[*].groupList.members[*]").Select(node => node.Value).ToList();
-        
-
-            return Ok(datas);
-
-
-            //            var schoolResult = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<string>("select value c.id from c ", "Base");
-            //            if (schoolResult.list.IsNotEmpty()) 
-            //            {
-            //                foreach (var item in schoolResult.list) {
-            //                    var courseResult = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<IdCode>($"select  c.id,c.code from c where contains(c.code,'StuCourse-{item}-') ");
-            //                    if(courseResult.list.IsNotEmpty()) {
-            //                        foreach (var course in courseResult.list) 
-            //                        {
-            //                           await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).DeleteItemStreamAsync(course.id, new PartitionKey(course.code));
-            //;                        }
-            //                    }
-            //                }
-            //            }
-            //string sql = "select value c from c where contains(c.code,'StuCourse-')";
-            //var courseResult = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<IdCode>(sql);
-            //if (courseResult.list.IsNotEmpty())
-            //{
-            //    foreach (var course in courseResult.list)
-            //    {
-            //        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).DeleteItemStreamAsync(course.id, new PartitionKey(course.code));
-            //    }
-            //}
+            Accumulate accumulate= json.ToObject<Accumulate>();
+            await SystemService.RecordAccumulateData(_azureRedis,_dingDing, accumulate);
             return Ok();
         }
 

+ 4 - 4
TEAMModelOS/TEAMModelOS.csproj

@@ -75,11 +75,11 @@
     <SpaRoot>ClientApp\</SpaRoot>
     <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
     <UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-    <Version>5.2402.28</Version>
-    <AssemblyVersion>5.2402.28.1</AssemblyVersion>
-    <FileVersion>5.2402.28.1</FileVersion>
+    <Version>5.2403.6</Version>
+    <AssemblyVersion>5.2403.6.1</AssemblyVersion>
+    <FileVersion>5.2403.6.1</FileVersion>
     <Description>TEAMModelOS(IES5)</Description>
-    <PackageReleaseNotes>IES版本说明版本切换标记5.2402.28.1</PackageReleaseNotes>
+    <PackageReleaseNotes>IES版本说明版本切换标记5.2403.6.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.2402.28.1"
+    "Version": "5.2403.6.1"
   },
   "Azure": {
 

+ 1 - 1
TEAMModelOS/appsettings.json

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