Prechádzať zdrojové kódy

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

CrazyIter_Bin 1 rok pred
rodič
commit
a31baf2390

+ 21 - 10
TEAMModelBI/Controllers/BINormal/BatchAreaController.cs

@@ -686,20 +686,31 @@ namespace TEAMModelBI.Controllers.BINormal
                 // 檢查是否有大寫或是中文字
                 if ( Regex.IsMatch(shortCode, @"[^a-z0-9]") )
                 {
-                    return Ok(new { state = 1, message = "此區級簡碼必須為小寫字母!" });
+                    return Ok(new { state = 1, message = "此区级简码必须为小写字母!" });
                 }             
 
                 string sqlCheckRep =  $"SELECT c.id FROM c WHERE c.shortCode = '{shortCode}'";
                 var _azureCosmosClientCsv2Read = _azureCosmos.GetCosmosClient(name: "CoreServiceV2CnRead");
-                await foreach (var item in _azureCosmosClientCsv2Read.GetContainer("Core", "School").GetItemQueryStreamIterator(queryText: sqlCheckRep, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("district") })) 
-                {
-                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetInt16() > 0)
-                    {
-                        return Ok(new { state = 1, message = "区级名称相同,请检测区级名称!" });
-                    }                    
-                }
-                
+                //學校資料庫驗證 [式樣待確認,先封印]
+                ///學區簡碼重複驗證
+                //await foreach (var item in _azureCosmosClientCsv2Read.GetContainer("Core", "School").GetItemQueryStreamIterator(queryText: sqlCheckRep, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("district") })) 
+                //{
+                //    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                //    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetInt16() > 0)
+                //    {
+                //        return Ok(new { state = 1, message = "此学区简码与其他 [学区] 简码相同请检查!" });
+                //    }                    
+                //}
+                ///學校簡碼重複驗證
+                //await foreach (var item in _azureCosmosClientCsv2Read.GetContainer("Core", "School").GetItemQueryStreamIterator(queryText: sqlCheckRep, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("base") }))
+                //{
+                //    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                //    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetInt16() > 0)
+                //    {
+                //        return Ok(new { state = 1, message = "此学区简码与其他 [学校] 简码相同请检查!" });
+                //    }
+                //}
+
                 //DB值更新
                 if (!string.IsNullOrWhiteSpace(name)) area.name = name;
                 if (!string.IsNullOrWhiteSpace(shortCode)) area.shortCode = shortCode;

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

@@ -296,10 +296,14 @@ export default {
 			})
 		})
     },
-    // 获取错题新增
+    // 获取错题数
     getErrorItemCnt: function(data) {
         return post("/common/exam/get-error-item-cnt", data)
     },
+    // 获取错题新增数
+    getErrorItemToday: function(data) {
+        return post("/common/exam/get-error-item-today-cnt", data)
+    },
     // 课程——新增话题
     addTopic: function(data) {
         return post("/school/debate/upsert", data)

+ 5 - 1
TEAMModelOS/ClientApp/src/components/student-web/WrongQusetion/QuesList.vue

@@ -261,8 +261,12 @@ export default {
             let param = {
                 stuId: this.userInfo.sub,
                 subjectId: this.courseNow.subject.id ? this.courseNow.subject.id : this.courseNow.id,
+                teacherId: this.courseNow.teacherId
+            }
+            //if(this.userInfo.scope != 'tmduser') param.code = this.userInfo.azp
+            if(this.userInfo.scope === 'student') {
+                param.code = this.courseNow.school
             }
-            if(this.userInfo.scope != 'tmduser') param.code = this.userInfo.azp
             this.$api.studentWeb.getErrorItemCnt(param).then(res => {
                 if(res.avaliable) {
                     this.topicTotal = res.avaliable

+ 13 - 1
TEAMModelOS/ClientApp/src/components/student-web/WrongQusetion/WrongQues.vue

@@ -147,7 +147,7 @@ export default {
             this.isReview = true
         },
         getErrorNum() {
-            let param = {
+            /* let param = {
                 stuId: this.userInfo.sub,
                 subjectId: this.courseNow.subject.id ? this.courseNow.subject.id : this.courseNow.id,
             }
@@ -156,7 +156,19 @@ export default {
                 if(res.avaliable && res.avaliable > res.record) {
                     this.dayAdd = res.avaliable - res.record
                 }
+            }) */
+            // 改用 get-error-item-today-cnt
+            let param = {
+                stuId: this.userInfo.sub,
+                subjectId: this.courseNow.subject.id ? this.courseNow.subject.id : this.courseNow.id,
+                code: this.userInfo.scope != 'tmduser' ? this.userInfo.azp : null
+            }
+            this.$api.studentWeb.getErrorItemToday(param).then(res => {
+                if(res.avaliable) {
+                    this.dayAdd = res.avaliable
+                }
             })
+            
         },
         startReview(type) {
             this.isLoading = true

+ 4 - 1
TEAMModelOS/ClientApp/src/view/learnactivity/byStu/ByStuMark.vue

@@ -227,6 +227,8 @@ export default {
           }
           this.studentAnswer.status = true
         }
+        // 切换学生后,上面步骤会触发studentAnswer.scores的监控事件,需重置编辑(isUpd)状态,否则会下一次切换学生时保存成绩
+        this.isUpd = false
       },
       deep: true,
       immediate: true
@@ -421,7 +423,8 @@ export default {
           this.$Message.success(this.$t('learnActivity.score.saveScoreOk'))
           this.isUpd = false
           this.$emit('updScore', [d])
-          if (!this.studentAnswer.scores.includes(-1)) {
+          // 切换学生时保存成绩,不需要展示下一位学生页面
+          if (!this.studentAnswer.scores.includes(-1) && this.studentInfo.id === requestData.studentId[0].id) {
             this.isComplete = true
           }
           if (res.isScore) this.$EventBus.$emit('onStatusChange')

+ 3 - 0
TEAMModelOS/ClientApp/src/view/learnactivity/tabs/AnswerTable.vue

@@ -446,6 +446,9 @@ export default {
                 }
                 if (n.papers && n.papers.length) {
                     if (n.owner == 'school') { //**现在不能通过scope判断是校本还是个人发布的评测,后面讨论添加了owner字段区分个人评测还是校本评测
+                        // 艺术评测id固定为subject_painting、subject_music
+                        // 和paperl里的科目id不一样
+                        // 暂不处理
                         let res = n.papers.find((item) => {
                             return item.subjectId == this.chooseSubject;
                         });

+ 1 - 2
TEAMModelOS/ClientApp/src/view/signupActivity/createActivity.vue

@@ -56,9 +56,8 @@
                                 <Icon type="md-alert" color="#ffad16" size="18" />
                                 不选学校则表示所有学校都可参加该活动
                             </p>
-                            <p>
+                            <p v-show="(createData.scope === 'public' && selSchools.length) || createData.scope != 'public'">
                                 <Icon type="ios-alert-outline" color="#ffad16" size="18" />
-                                <!-- <Icon type="ios-alert" color="#ffad16" size="18" /> -->
                                 发布活动后,需学校先确认参与活动,老师才可报名参与
                             </p>
                         </FormItem>

+ 55 - 37
TEAMModelOS/ClientApp/src/view/student-web/AppNew.vue

@@ -57,59 +57,77 @@
                         <span class="no-show" v-show="MyNo != 2">{{ $t('studentWeb.course') }}</span>
                     </MenuItem> -->
                     <!-- 课堂记录 -->
-                    <MenuItem name="10" to="/studentWeb/classRecord" :title="$t('studentWeb.courseContent.classRecord')"
-                            v-show="getNowCourse && getNowCourse.id && selectClass && !onlySystem && getNowCourse.subject && !isScale"
-                    >
-                        <svg-icon icon-class="course" class="tabIcon1" />
-                        <span class="no-show" v-show="MyNo != 10">{{ $t('studentWeb.courseContent.classRecord') }}</span>
-                    </MenuItem>
+                    <Tooltip :content="$t('studentWeb.courseContent.classRecord')">
+                        <MenuItem name="10" to="/studentWeb/classRecord"
+                                v-show="getNowCourse && getNowCourse.id && selectClass && !onlySystem && getNowCourse.subject && !isScale"
+                        >
+                            <svg-icon icon-class="course" class="tabIcon1" />
+                            <span class="no-show" v-show="MyNo != 10">{{ $t('studentWeb.courseContent.classRecord') }}</span>
+                            
+                        </MenuItem>
+                    </Tooltip>
                     <!-- 评测 -->
-                    <MenuItem name="5" to="/studentWeb/examView" :title="$t('studentWeb.type.exam')" v-show="selectClass">
-                        <svg-icon icon-class="test" class="tabIcon3" />
-                        <span class="no-show" v-show="MyNo != 5">{{ $t('studentWeb.type.exam') }}</span>
-                    </MenuItem>
+                    <Tooltip :content="$t('studentWeb.type.exam')">
+                        <MenuItem name="5" to="/studentWeb/examView" v-show="selectClass">
+                            <svg-icon icon-class="test" class="tabIcon3" />
+                            <span class="no-show" v-show="MyNo != 5">{{ $t('studentWeb.type.exam') }}</span>
+                        </MenuItem>
+                    </Tooltip>
                     <!-- 作业 -->
-                    <MenuItem name="6" to="/studentWeb/homeworkView" :title="$t('studentWeb.type.homework')" v-show="selectClass && !isScale">
-                        <svg-icon icon-class="doc" class="tabIcon3" />
-                        <span class="no-show" v-show="MyNo != 6">{{ $t('studentWeb.type.homework') }}</span>
-                    </MenuItem>
+                    <Tooltip :content="$t('studentWeb.type.homework')">
+                        <MenuItem name="6" to="/studentWeb/homeworkView" v-show="selectClass && !isScale">
+                            <svg-icon icon-class="doc" class="tabIcon3" />
+                            <span class="no-show" v-show="MyNo != 6">{{ $t('studentWeb.type.homework') }}</span>
+                        </MenuItem>
+                    </Tooltip>
                     <!-- <MenuItem name="9" to="/studentWeb/studyView" :title="$t('studentWeb.type.studyview')">
                         <svg-icon icon-class="note" class="tabIcon2" />
                         <span class="no-show" v-show="MyNo != 9">{{ $t('studentWeb.type.studyview') }}</span>
                     </MenuItem> -->
                     <!-- 活动 -->
-                    <MenuItem name="3" to="/studentWeb/eventView" :title="$t('studentWeb.type.activity')" v-show="!isScale">
-                        <svg-icon icon-class="selflearning" class="tabIcon4" />
-                        <span class="no-show" v-show="MyNo != 3">{{ $t('studentWeb.type.activity') }}</span>
-                    </MenuItem>
+                    <Tooltip :content="$t('studentWeb.type.activity')">
+                        <MenuItem name="3" to="/studentWeb/eventView" v-show="!isScale">
+                            <svg-icon icon-class="selflearning" class="tabIcon4" />
+                            <span class="no-show" v-show="MyNo != 3">{{ $t('studentWeb.type.activity') }}</span>
+                        </MenuItem>
+                    </Tooltip>
                     <!-- 错题本(搭配学校卖出,限制学生才能使用) -->
                     <!-- 先放开醍摩豆登录限制,方便老师体验试用 -->
-                    <!-- <MenuItem v-if="userInfo.scope === 'student'" name="8" to="/studentWeb/practice/wrongQues" :title="$t('studentWeb.type.wrongTopic')" -->
-                    <MenuItem name="8" to="/studentWeb/practice/wrongQues" :title="$t('studentWeb.type.wrongTopic')"
-                            v-show="getNowCourse && getNowCourse.id && selectClass && !onlySystem && getNowCourse.subject && !isScale">
-                        <Icon custom="iconfont icon-cuotiji" size="17" class="tabIcon1" />
-                        <span class="no-show" v-show="MyNo != 8">{{ $t('studentWeb.type.wrongTopic') }}</span>
-                    </MenuItem>
-                    <MenuItem name="14" to="/studentWeb/discussionBoard" :title="$t('studentWeb.type.discussionBoard')"
-                            v-show="getNowCourse && getNowCourse.id && selectClass && !onlySystem && getNowCourse.subject && !isScale">
-                        <Icon type="ios-chatboxes-outline" size="18" style="font-weight: bold" />
-                        <span class="no-show" v-show="MyNo != 14">{{ $t('studentWeb.type.discussionBoard') }}</span>
-                    </MenuItem>
+                    <Tooltip :content="$t('studentWeb.type.wrongTopic')">
+                        <!-- <MenuItem v-if="userInfo.scope === 'student'" name="8" to="/studentWeb/practice/wrongQues" :title="$t('studentWeb.type.wrongTopic')" -->
+                        <MenuItem name="8" to="/studentWeb/practice/wrongQues"
+                                v-show="getNowCourse && getNowCourse.id && selectClass && !onlySystem && getNowCourse.subject && !isScale">
+                            <Icon custom="iconfont icon-cuotiji" size="17" class="tabIcon1" />
+                            <span class="no-show" v-show="MyNo != 8">{{ $t('studentWeb.type.wrongTopic') }}</span>
+                        </MenuItem>
+                    </Tooltip>
+                    <!-- 讨论区 -->
+                    <Tooltip :content="$t('studentWeb.type.discussionBoard')">
+                        <MenuItem name="14" to="/studentWeb/discussionBoard"
+                                v-show="getNowCourse && getNowCourse.id && selectClass && !onlySystem && getNowCourse.subject && !isScale">
+                            <Icon type="ios-chatboxes-outline" size="18" style="font-weight: bold" />
+                            <span class="no-show" v-show="MyNo != 14">{{ $t('studentWeb.type.discussionBoard') }}</span>
+                        </MenuItem>
+                    </Tooltip>
                     <!-- 精准练习 -->
                     <!-- <MenuItem name="12" to="/studentWeb/practice/preciseQues" :title="$t('studentWeb.type.wrongTopic1')" v-show="selectClass && !onlySystem && getNowCourse.subject">
                         <Icon custom="iconfont icon-cuotiji" size="17" class="tabIcon1" />
                         <span class="no-show" v-show="MyNo != 12">{{ $t('studentWeb.type.wrongTopic1') }}</span>
                     </MenuItem> -->
                     <!-- 成绩 -->
-                    <MenuItem name="7" to="/studentWeb/achievement" :title="$t('studentWeb.type.achievement')" v-show="selectClass && !isScale">
-                        <Icon custom="iconfont icon-chengjitongji" size="18" style="font-weight: bold" />
-                        <span class="no-show" v-show="MyNo != 7">{{ $t('studentWeb.type.achievement') }}</span>
-                    </MenuItem>
+                    <Tooltip :content="$t('studentWeb.type.achievement')">
+                        <MenuItem name="7" to="/studentWeb/achievement" v-show="selectClass && !isScale">
+                            <Icon custom="iconfont icon-chengjitongji" size="18" style="font-weight: bold" />
+                            <span class="no-show" v-show="MyNo != 7">{{ $t('studentWeb.type.achievement') }}</span>
+                        </MenuItem>
+                    </Tooltip>
                     <!-- 首页 -->
-                    <MenuItem name="1" to="/studentWeb/homeView" :title="$t('studentWeb.type.home')">
-                        <svg-icon icon-class="home" class="tabIcon2" />
-                        <span class="no-show" v-show="MyNo != 1">{{ $t('studentWeb.type.home') }}</span>
-                    </MenuItem>
+                    <Tooltip :content="$t('studentWeb.type.home')">
+                        <MenuItem name="1" to="/studentWeb/homeView">
+                            <svg-icon icon-class="home" class="tabIcon2" />
+                            <span class="no-show" v-show="MyNo != 1">{{ $t('studentWeb.type.home') }}</span>
+                        </MenuItem>
+                    </Tooltip>
                 </Menu>
                 <!-- 头像 -->
                 <div class="profile-dropdown">

+ 15 - 15
TEAMModelOS/Controllers/Both/ScoreCalcController.cs

@@ -2586,14 +2586,14 @@ namespace TEAMModelOS.Controllers
 
                 // 先排序傳進來的參數 aesc
                 List<sortItem> sortItemsrq = (from e in updateActItemSortRq.sortItems
-                                              orderby e.sort
-                                              select e).ToList();
+                                                orderby e.sort
+                                                select e).ToList();
 
                 // 先判斷是否為課堂紀錄 根據項目的類別需要調整
                 if (scoreCalcActivityBase.type == "lessonrecord")
                 {
                     ScoreCalcLsRecord scoreCalcLsRecordDB = await clientTeacher.ReadItemAsync<ScoreCalcLsRecord>(updateActItemSortRq.scoreCalcActId.ToString(), new PartitionKey($"ScoreCalcAct-{teammodelId}"));
-
+                    
                     //存放排序後的參數
                     List<List<double>> up_stuActAttendOrgVals = new();
                     List<List<double>> up_stuActAttendScores = new();
@@ -2604,11 +2604,11 @@ namespace TEAMModelOS.Controllers
                     List<double> up_itemRates = new();
 
                     //依照傳進來的id 順序修改 分數 比重 項目等順序
-                    for (int i = 0; i < sortItemsrq.Count; i++)
+                    for (int i = 0; i < sortItemsrq.Count; i++) 
                     {
                         for (int j = 0; j < scoreCalcLsRecordDB.items.Count; j++)
                         {
-                            if (sortItemsrq[i].id == scoreCalcLsRecordDB.items[j].id)
+                            if (sortItemsrq[i].id == scoreCalcLsRecordDB.items[j].id) 
                             {
                                 up_stuActAttendOrgVals.Add(scoreCalcLsRecordDB.stuActAttendOrgVals[j]);
                                 up_stuActAttendScores.Add(scoreCalcLsRecordDB.stuActAttendScores[j]);
@@ -2617,7 +2617,7 @@ namespace TEAMModelOS.Controllers
                                 up_stuActItactOrgVals.Add(scoreCalcLsRecordDB.stuActItactOrgVals[j]);
                                 up_stuActItactScores.Add(scoreCalcLsRecordDB.stuActItactScores[j]);
                                 up_itemRates.Add(scoreCalcLsRecordDB.itemRates[j]);
-                                scoreCalcLsRecordDB.items[j].sort = sortItemsrq[i].sort;
+                                scoreCalcLsRecordDB.items[j].sort = sortItemsrq[i].sort;                                
                             }
                         }
 
@@ -2631,17 +2631,17 @@ namespace TEAMModelOS.Controllers
                     scoreCalcLsRecordDB.itemRates = up_itemRates;
                     // 按照更新後的sort排序
                     scoreCalcLsRecordDB.items = (from e in scoreCalcLsRecordDB.items
-                                                 orderby e.sort
-                                                 select e).ToList();
-
+                                                  orderby e.sort
+                                                  select e).ToList();
+                    
                     scoreCalcLsRecordDB = await clientTeacher.ReplaceItemAsync(scoreCalcLsRecordDB, $"{scoreCalcLsRecordDB.id}", new PartitionKey(scoreCalcLsRecordDB.code));
                 }
                 else
                 {
                     ScoreCalcActivity scoreCalcActivityDB = await clientTeacher.ReadItemAsync<ScoreCalcActivity>(updateActItemSortRq.scoreCalcActId.ToString(), new PartitionKey($"ScoreCalcAct-{teammodelId}"));
-
+                    
                     //存放排序後的參數
-                    List<List<double>> up_stuActScores = new();
+                    List<List<double>> up_stuActScores =new();
                     List<List<double>> up_stuActScoresOrg = new();
                     List<double> up_itemRates = new();
 
@@ -2664,9 +2664,9 @@ namespace TEAMModelOS.Controllers
                     scoreCalcActivityDB.itemRates = up_itemRates;
                     // 按照更新後的sort排序
                     scoreCalcActivityDB.items = (from e in scoreCalcActivityDB.items
-                                                 orderby e.sort
-                                                 select e).ToList();
-
+                                                  orderby e.sort
+                                                  select e).ToList();
+                    
                     scoreCalcActivityDB = await clientTeacher.ReplaceItemAsync(scoreCalcActivityDB, $"{scoreCalcActivityDB.id}", new PartitionKey(scoreCalcActivityDB.code));
                 }
 
@@ -2684,7 +2684,7 @@ namespace TEAMModelOS.Controllers
                 return BadRequest();
             }
         }
-
+        
 
         /// <summary>
         /// (十七)查詢項目屬性資料

+ 99 - 14
TEAMModelOS/Controllers/Common/ExamController.cs

@@ -38,6 +38,7 @@ using TEAMModelOS.SDK.Models.Cosmos.Student;
 using DocumentFormat.OpenXml.Drawing.Charts;
 using ClouDASLibx;
 using HTEXLib.Helpers.ShapeHelpers;
+using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 
 namespace TEAMModelOS.Controllers
 {
@@ -3701,17 +3702,18 @@ namespace TEAMModelOS.Controllers
             if (!request.TryGetProperty("subjectId", out JsonElement subjectId)) return BadRequest();
             string code = (request.TryGetProperty("code", out JsonElement codeJobj)) ? codeJobj.GetString() : string.Empty;
             string schCode = (!string.IsNullOrWhiteSpace(code)) ? code : "noschoolid";
-            //取得Redis該學生該科目的錯題數
+            string teacherid = (request.TryGetProperty("teacherId", out JsonElement teacherId)) ? teacherId.GetString() : string.Empty;
+            //取得Redis該學生該科目的錯題數 [算法變更,昨日錯題總數不再計入redis]
             int record = 0; //昨日取得的錯題數
-            var redisClient = _azureRedis.GetRedisClient(8);
-            string hkey = $"ErrorItems:{schCode}";
-            string hval = await redisClient.HashGetAsync(hkey, $"{stuId}");
-            List<stuErrorItemCnt> stuErrCntList = (hval != null) ? JsonSerializer.Deserialize<List<stuErrorItemCnt>>(hval) : new List<stuErrorItemCnt>();
-            stuErrorItemCnt stuErrCnt = stuErrCntList.Where(s => s.subjectId.Equals($"{subjectId}")).FirstOrDefault();
-            if (stuErrCnt != null)
-            {
-                record = stuErrCnt.number;
-            }
+            //var redisClient = _azureRedis.GetRedisClient(8);
+            //string hkey = $"ErrorItems:{schCode}";
+            //string hval = await redisClient.HashGetAsync(hkey, $"{stuId}");
+            //List<stuErrorItemCnt> stuErrCntList = (hval != null) ? JsonSerializer.Deserialize<List<stuErrorItemCnt>>(hval) : new List<stuErrorItemCnt>();
+            //stuErrorItemCnt stuErrCnt = stuErrCntList.Where(s => s.subjectId.Equals($"{subjectId}")).FirstOrDefault();
+            //if (stuErrCnt != null)
+            //{
+            //    record = stuErrCnt.number;
+            //}
             //取得CosmosDB該學生該科目現在錯題數
             int avaliable = 0; //現在取得的錯題數
             List<string> itemIdList = new List<string>();
@@ -3779,14 +3781,97 @@ namespace TEAMModelOS.Controllers
 
             foreach (var obj in dict)
             {
-                if (_azureStorage.GetBlobContainerClient(schCode).GetBlobClient($"{obj.Value}/{obj.Key}.json").Exists())
-                {// 去除blob不存在項目
-                    avaliable++;
+                if (schCode != null && schCode != "noschoolid")
+                {
+                    if (_azureStorage.GetBlobContainerClient(schCode).GetBlobClient($"{obj.Value}/{obj.Key}.json").Exists())
+                    {// 去除blob不存在項目
+                        avaliable++;
+                    }
+                }
+                else if (!string.IsNullOrWhiteSpace(teacherid))
+                {
+                    if (_azureStorage.GetBlobContainerClient(teacherid).GetBlobClient($"{obj.Value}/{obj.Key}.json").Exists())
+                    {
+                        avaliable++;
+                    }
                 }
             }
-
             return Ok(new { record, avaliable });
         }
+
+        //取得錯題庫新增數
+        [ProducesDefaultResponseType]
+        [Authorize(Roles = "IES")]
+        [AuthToken(Roles = "teacher,admin,student")]
+        [HttpPost("get-error-item-today-cnt")]
+        public async Task<IActionResult> getErrorItemsTodayCount(JsonElement request)
+        {
+            //輸入值
+            if (!request.TryGetProperty("subjectId", out JsonElement subjectId)) return BadRequest(); //科目ID
+            if (!request.TryGetProperty("stuId", out JsonElement _stuId)) return BadRequest(); //學生ID 或 TMID
+            string stuId = _stuId.GetString();
+            string schoolid = (request.TryGetProperty("code", out JsonElement codeJobj)) ? codeJobj.GetString() : string.Empty; //學校簡碼,TMID時為空
+            string tmdid = string.Empty;
+            if (string.IsNullOrWhiteSpace(schoolid)) tmdid = stuId;
+            string maLearnCode = string.Empty;
+            //檢查參數 必須有 teammodelId 或是同時有學校id及學號
+            if (!string.IsNullOrWhiteSpace(tmdid + ""))
+            {
+                maLearnCode = $"MaLearn-{tmdid}";
+            }
+            else if (!string.IsNullOrWhiteSpace(schoolid + "") && !string.IsNullOrWhiteSpace(stuId + ""))
+            {
+                maLearnCode = $"MaLearn-{schoolid}-{stuId}";
+            }
+            else { return BadRequest(); }
+
+            DateTime nowDate = DateTime.Now;
+            DateTime beforeDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 0, 0, 0);
+            string qry_All = $"SELECT COUNT(1) as num FROM c WHERE c.type = 'answer' AND c.unitId = '{subjectId}' AND IS_DEFINED(c.createdTime) AND c.createdTime <= {DateTimeHelper.ToUnixTimestamp(nowDate)}";
+            string qry_before = $"SELECT COUNT(1) as num FROM c WHERE c.type = 'answer' AND c.unitId = '{subjectId}' AND IS_DEFINED(c.createdTime) AND c.createdTime <= {DateTimeHelper.ToUnixTimestamp(beforeDate)}  ";
+            var client = _azureCosmos.GetCosmosClient();
+            int avaliable = 0;
+            int allNum = 0;
+            int berforeNum = 0;
+
+            // 取全部錯題數量
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: qry_All, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{maLearnCode}") }))
+            {
+                using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                {
+                    foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                    {
+                        if (obj.TryGetProperty("num", out JsonElement num))
+                        {
+                            allNum = num.GetInt32();
+                        }
+                    }
+                }
+            }
+            // 取今天之前錯題的數量
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: qry_before, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{maLearnCode}") }))
+            {
+                using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                {
+                    foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                    {
+                        if (obj.TryGetProperty("num", out JsonElement num))
+                        {
+                            berforeNum = num.GetInt32();
+                        }
+                    }
+                }
+            }
+
+            avaliable = allNum - berforeNum;
+
+            return Ok(new { avaliable });
+        }
+
+
+
         //阅卷信息统计
         [ProducesDefaultResponseType]
         [Authorize(Roles = "IES")]