Parcourir la source

Merge branch 'develop' into develop-rc

CrazyIter_Bin il y a 2 ans
Parent
commit
eaa265bc06
23 fichiers modifiés avec 1067 ajouts et 475 suppressions
  1. 1 1
      TEAMModelBI/ClientApp/public/index.html
  2. 78 11
      TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue
  3. 6 4
      TEAMModelBI/ClientApp/src/view/areaServe/setthird.vue
  4. 22 7
      TEAMModelBI/ClientApp/src/view/product/index.vue
  5. 3 2
      TEAMModelBI/Controllers/BINormal/BatchAreaController.cs
  6. 12 6
      TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs
  7. 16 1
      TEAMModelOS/ClientApp/public/lang/en-US.js
  8. 15 0
      TEAMModelOS/ClientApp/public/lang/zh-CN.js
  9. 15 0
      TEAMModelOS/ClientApp/public/lang/zh-TW.js
  10. 8 0
      TEAMModelOS/ClientApp/src/api/lessonRecord.js
  11. 1 1
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReportCharts/LessonTestReportCharts.vue
  12. 4 1
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperViewBox/PaperView.vue
  13. 6 3
      TEAMModelOS/ClientApp/src/components/student-web/WrongQusetion/WrongQues.vue
  14. 6 0
      TEAMModelOS/ClientApp/src/css/common-style.less
  15. 32 0
      TEAMModelOS/ClientApp/src/view/homepage/HomePage.less
  16. 726 414
      TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue
  17. 0 1
      TEAMModelOS/ClientApp/src/view/homepage/SpaceInfo.vue
  18. 2 2
      TEAMModelOS/Controllers/Common/ExamController.cs
  19. 106 13
      TEAMModelOS/Controllers/System/BlobController.cs
  20. 2 2
      TEAMModelOS/Controllers/XTest/TestController.cs
  21. 4 4
      TEAMModelOS/TEAMModelOS.csproj
  22. 1 1
      TEAMModelOS/appsettings.Development.json
  23. 1 1
      TEAMModelOS/appsettings.json

+ 1 - 1
TEAMModelBI/ClientApp/public/index.html

@@ -12,7 +12,7 @@
     </title>
 </head>
 <script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
-<script src="https://at.alicdn.com/t/c/font_2934132_3s3ctw0yifz.js"></script>
+<script src="https://at.alicdn.com/t/c/font_2934132_qg08bz6d3ll.js"></script>
 <script src="../src/access/iconfont.js"></script>
 
 <body>

+ 78 - 11
TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue

@@ -46,6 +46,10 @@
                     </el-select>
                 </div> -->
       </div>
+      <div class="areaschoolCount">
+          <span class="areaschoolCount-title">学区数量:</span>
+          <span class="areaschoolCount-num">{{optionData.length}}</span>
+      </div>
       <div class="boxselect" v-if="PowerShow">
         <!-- <a>
                     <div class="layer">
@@ -129,18 +133,22 @@
                     </el-dropdown>
                   </div>
                   <div class="search-school">
-                    <el-input v-model="schoolSeach" placeholder="输入学校名称搜索" clearable>
-                      <!-- <template #prepend>
-                        <svg class="addrelevancy-icon" aria-hidden="true">
-                          <use xlink:href="#icon-sousuo3-copy"></use>
-                        </svg>
-                      </template> -->
+                    <el-input v-model="schoolSeach" placeholder="输入学校名称搜索" clearable v-if="!multiplecheck">
                     </el-input>
+                    <el-button type="primary" v-else-if="multiplecheck" @click="multipleAdd">
+                      <svg class="multipleicon" aria-hidden="true">
+                        <use xlink:href="#icon-piliangtianjia1"></use>
+                      </svg>
+                      批量添加
+                    </el-button>  
                   </div>
                   <div class="synchronization-title" v-show="currentlySelect.cutArea"><span>已同步省平台</span></div>
                 </div>
                 <ul>
                   <li class="details-list-school" v-for="(item, index) in notjoinSchool" :key="item.id" :class="{ active: position === index }">
+                    <div class="details-list-checkboxs" @change="multipleChange">
+                      <el-checkbox v-model="item.checkstate"/>
+                    </div>
                     <div class="list-school-logo">
                       <el-image :src="item.picture" fit="fill" v-if="item.picture"> </el-image>
                       <div class="notimages" v-else>暂无图片</div>
@@ -742,6 +750,7 @@ export default {
     //未加入学区学校搜索
     let schoolSeach = ref('')
     let dropdownValue = ref('显示所有学校')
+    let multiplecheck=ref(false)
     onMounted(() => {
       provinceOptions.value.optionInfo = optionsData
     })
@@ -814,7 +823,7 @@ export default {
           //   ? (notjoinSchool.value = [], notjoinSchool.value = res.notAreaSchools, notjoinPrimitive.value = res.notAreaSchools, loadingSchoolList.value = false)
           //   : ''
           res.state === 200 ? 
-          (notjoinSchool.value = [],res.scInfos.forEach((item)=>{!item.areaId ? notaredSchool.push(item):''}),notjoinSchool.value=notaredSchool,notjoinPrimitive.value=notaredSchool,loadingSchoolList.value = false):
+          (notjoinSchool.value = [],res.scInfos.forEach((item)=>{!item.areaId ? notaredSchool.push(item):''}),notaredSchool.forEach((item)=>{item.checkstate=false}),notjoinSchool.value=notaredSchool,notjoinPrimitive.value=notaredSchool,loadingSchoolList.value = false):
           ''
         })
     }
@@ -1307,6 +1316,38 @@ export default {
       value === 'virtual' ? (dropdownValue.value = '只看虚拟学校',notjoinSchool.value=nowTables.filter((item)=>{return item.code ==='VirtualBase'})) : ''
       value === 'entity' ? (dropdownValue.value = '只看实体学校',notjoinSchool.value=nowTables.filter((item)=>{return item.code ==='BIRel'})) : ''
     }
+    //批量添加学校 checkbox变化出发
+    function multipleChange(val){
+      console.log(notjoinSchool.value,'学校')
+      let schoolList=notjoinSchool.value
+      let resultState=schoolList.every(item=>item.checkstate === false)
+      resultState ? multiplecheck.value=false: multiplecheck.value=true
+    }
+    //确认批量 学校加入学区
+    function multipleAdd(){
+      let schoolAll=notjoinSchool.value
+      let addSchoolcode=[];let addcode=[]
+      schoolAll.forEach((item)=>{
+         item.checkstate ? (addSchoolcode.push(item.id),addcode.push(item.code)):''
+      })
+      let data = {
+        schoolCode: addSchoolcode,
+        standard: currentlySelect.value.standard,
+        areaId: currentlySelect.value.id,
+        code: addcode,
+        // schoolCode: [schoolcode],
+      }
+      console.log(data,'批量准备提交的内容')
+      proxy.$api.areaAddSchool(data).then(async (res) => {
+        console.log(res, '区域加入学校返回')
+        res.state === 200
+          ? (ElMessage.success(proxy.$t(`commonMsg.addschoolSuccess`)), (addSchoolHint.value = false),
+            await getNotjoin(), notjoinSchoolarea(),
+            getAreaschool())
+          : res.state === 401 ? ElMessage.error('已同步省平台,无法加入学区') : ElMessage.error(proxy.$t(`commonMsg.addschoolError`))
+      })
+      position.value = ''
+    }
     watch(abilityModel, (newdata) => {
       console.log(newdata)
       newdata
@@ -1433,7 +1474,10 @@ export default {
       notjoinSchoolarea,
       notjoinPrimitive,
       handleCommand,
-      dropdownValue
+      dropdownValue,
+      multiplecheck,
+      multipleChange,
+      multipleAdd
     }
   },
 }
@@ -1445,9 +1489,12 @@ export default {
   /* background-color: #fff; */
   padding: 5px 10px;
 }
-
+.areaschoolCount{
+  width:10%;
+  display: inline-block;
+}
 .boxselect {
-  width: 20%;
+  width: 10%;
   display: inline-block;
   margin-top: 1.5%;
   padding-right: 1%;
@@ -1730,7 +1777,7 @@ export default {
   line-height: 60px;
   text-align: left;
   padding: 1%;
-  width: 75%;
+  width: 70%;
   float: left;
   font-weight: normal;
 }
@@ -1823,6 +1870,7 @@ export default {
 }
 .search-school {
   width: 45%;
+  text-align: center;
 }
 .search-school div {
   width: 100%;
@@ -2275,6 +2323,25 @@ export default {
   height: 60px !important;
   line-height: 60px !important;
 }
+.details-list-checkboxs,.list-school-type{
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  margin-right:2%;
+}
+.multipleicon{
+  width: 1.3em;
+  height: 1.3em;
+  vertical-align: -0.4em;
+  fill: currentColor;
+  overflow: hidden;
+  margin-right:2px;
+}
+.areaschoolCount-title,.areaschoolCount-num{
+  font-size: 14px;
+  color: #636e72;
+  font-weight: none;
+}
 </style>
 <style>
 .stagebox-table-not .el-image {

+ 6 - 4
TEAMModelBI/ClientApp/src/view/areaServe/setthird.vue

@@ -136,7 +136,7 @@
             <p class="set-basics-title">
             <div class="set-basics-title-name">关联用户</div>
             <div class="set-basics-save">
-              <el-button type="primary" size="small" @click="addschoolRelevancy=true" v-if="PowerShow">
+              <el-button type="primary" size="small" @click="addschoolAdmin=true" v-if="PowerShow">
                 <svg class="addrelevancy-icon" aria-hidden="true">
                   <use xlink:href="#icon-guanlianrenyuan"></use>
                 </svg>
@@ -221,7 +221,7 @@
     <!--添加关联学校弹窗end-->
     <!--添加关联用户弹窗-->
     <div class="adduser-relevancy">
-      <el-dialog v-model="addschoolRelevancy" title="搜索用户列表" width="25%">
+      <el-dialog v-model="addschoolAdmin" title="搜索用户列表" width="25%">
         <div>
           <el-input v-model="searchUser" placeholder="搜索 手机号码" class="input-with-select" size="small" clearable>
             <template #prepend>
@@ -250,7 +250,7 @@
         </el-table>
         <template #footer>
           <span class="dialog-footer">
-            <el-button @click="addschoolRelevancy = false">取消</el-button>
+            <el-button @click="addschoolAdmin = false">取消</el-button>
             <el-button type="primary" @click="notarizebox=true">关联选中用户</el-button>
           </span>
         </template>
@@ -326,6 +326,7 @@ export default {
     let original = ref([])
     let timer = ref('')
     let addschoolRelevancy = ref(false)
+    let addschoolAdmin=ref(false)
     let checkedSchool = ref([])
     let checkedUser = ref([])
     let removeArr = ref([])
@@ -682,7 +683,8 @@ export default {
       correlationRole,
       removeUser,
       removeUserarr,
-      removeUserList
+      removeUserList,
+      addschoolAdmin
     }
   },
 }

+ 22 - 7
TEAMModelBI/ClientApp/src/view/product/index.vue

@@ -169,7 +169,7 @@
     <div class="data-tables">
       <el-auto-resizer>
         <template #default="{ height, width }">
-          <el-table-v2 :columns="columns" :data="filterdata" :width="width" :height="height" :sort-by="sortState" @column-sort="onSort" fixed />
+          <el-table-v2 v-model:sort-state="sortState" :columns="columns" :data="filterdata" :width="width" :height="height" @column-sort="onSort" fixed />
         </template>
       </el-auto-resizer>
     </div>
@@ -303,6 +303,7 @@ let columns = ref([
     title: "教室数",//显示在单元格表头的文本
     width: 100,//当前列的宽度,必须设置
     headerClass: 'general',
+    sortable:true
   },
   {
     key: "tmidCnt",
@@ -310,6 +311,7 @@ let columns = ref([
     title: "教师数",//显示在单元格表头的文本
     width: 100,//当前列的宽度,必须设置
     headerClass: 'general',
+    sortable:true
   },
   {
     key: "stuShow",
@@ -317,6 +319,7 @@ let columns = ref([
     title: "学生人数",//显示在单元格表头的文本
     width: 100,//当前列的宽度,必须设置
     headerClass: 'general',
+    sortable:true
   },
   {
     key: "lessonRecord",
@@ -324,6 +327,7 @@ let columns = ref([
     title: "课堂总数",//显示在单元格表头的文本
     width: 100,//当前列的宽度,必须设置
     headerClass: 'general',
+    sortable:true
   },
   {
     key: "lessonLengMin",
@@ -331,6 +335,7 @@ let columns = ref([
     title: "课堂总时数",//显示在单元格表头的文本
     width: 100,//当前列的宽度,必须设置
     headerClass: 'general',
+    sortable:true
   },
   {
     key: "tGreen",
@@ -338,6 +343,7 @@ let columns = ref([
     title: "T绿灯",//显示在单元格表头的文本
     width: 100,//当前列的宽度,必须设置
     headerClass: 'general',
+    sortable:true
   },
   {
     key: "date",
@@ -345,6 +351,7 @@ let columns = ref([
     title: "时间",
     width: 100,
     headerClass: 'general',
+    sortable:true
   },
   {
     key: "handle",
@@ -391,13 +398,21 @@ columns.value[0].headerCellRenderer = (props = HeaderCellSlotProps) => {
       )
     }
 const sortState = ref({
-  key: 'name',
-  order: TableV2SortOrder.ASC,
+  'deviceCnt':TableV2SortOrder.ASC,
+  'tmidCnt': TableV2SortOrder.ASC,
+  'stuShow': TableV2SortOrder.ASC,
+  'lessonRecord':TableV2SortOrder.ASC,
+  'lessonLengMin':TableV2SortOrder.ASC,
+  'tGreen':TableV2SortOrder.ASC,
+  'date':TableV2SortOrder.ASC,
 })
-const onSort = (sortBy) => {
-  console.log(sortBy)
-  filterdata.value = filterdata.value.reverse()
-  sortState.value = sortBy
+const onSort = ({key,order}) => {
+  console.log(key,order)
+  sortState.value[key] = order
+  let field=key;let modes=order;let allData=filterdata.value
+  modes === 'desc' ? allData.sort((a,b)=> b[field]-a[field]): allData.sort((a,b)=> a[field]-b[field])
+  filterdata.value=allData
+  console.log(allData)
 }
 const searchColumns = [
   {

+ 3 - 2
TEAMModelBI/Controllers/BINormal/BatchAreaController.cs

@@ -170,8 +170,9 @@ namespace TEAMModelBI.Controllers.BINormal
                 foreach (var area in areas)
                 {
                     //select value(count(c.id)) from c where c.areaId='{area.id}' and c.standard='{area.standard}'
-                    area.schoolCount = await CommonFind.GetSqlValueCount(cosmosClient, "School", $"select value(count(c.id)) from c where c.areaId='{area.id}'", "Base");
-
+                    int baseCount = await CommonFind.GetSqlValueCount(cosmosClient, "School", $"select value(count(c.id)) from c where c.areaId='{area.id}'", "Base");
+                    int virtualCount = await CommonFind.GetSqlValueCount(cosmosClient, "School", $"select value(count(c.id)) from c where c.areaId='{area.id}'", "VirtualBase");
+                    area.schoolCount = baseCount + virtualCount;
                     area.aquoteRec = await table.QueryWhereString<AreaQuoteRecord>($"PartitionKey eq 'QuoteRecord' and  areaId eq '{area.id}'");
                     //List<AreaQuoteRecord> aqr = await table.QueryWhereString<AreaQuoteRecord>($"PartitionKey eq 'QuoteRecord' and  areaId eq '{area.id}'");
                     //aqr.Sort((x, y) => y.RowKey.CompareTo(x.RowKey));

+ 12 - 6
TEAMModelOS.FunctionV4/CosmosDB/TriggerExam.cs

@@ -611,7 +611,7 @@ namespace TEAMModelOS.FunctionV4
                     {
                         int index = examResult.studentIds.IndexOf(id);
                         score += examResult.studentScores[index].Sum();
-                    }                  
+                    }
                 }
 
                 stuCount = total - losStu.Count;
@@ -1319,6 +1319,14 @@ namespace TEAMModelOS.FunctionV4
                                 lostStu.Add(classResult.studentIds[index_stu]);
                             }
                         }
+                        else {
+                            if (classResult.status[index_stu] == 1) {
+                                if (!lostStu.Contains(classResult.studentIds[index_stu]))
+                                {
+                                    lostStu.Add(classResult.studentIds[index_stu]);
+                                }
+                            }
+                        }
                         index_stu++;
                     }
                     int index = 0;
@@ -1387,6 +1395,7 @@ namespace TEAMModelOS.FunctionV4
                 }
             }*/
             //处理人员变更时被移除的人员
+            result.lostStus = lostStu;
             if (result.lostStus.Count > 0)
             {
                 for (int i = 0; i < result.lostStus.Count; i++)
@@ -1397,7 +1406,6 @@ namespace TEAMModelOS.FunctionV4
                     }
                 }
             }
-            result.lostStus = lostStu;
             result.record = getMore(info, no, opt);
             result.average = result.studentIds.Count - result.lostStus.Count > 0 ? Math.Round(score * 1.0 / (result.studentIds.Count - result.lostStus.Count), 2) : 0;
             double powSum = 0;
@@ -1405,11 +1413,9 @@ namespace TEAMModelOS.FunctionV4
             result.studentIds.ForEach(x =>
             {
                 double sc = result.studentScores[result.studentIds.IndexOf(x)].Sum();
-                if (sc > 0)
-                {
+                if (!result.lostStus.Contains(x)) {
                     powSum += Math.Pow(sc - result.average, 2);
-                }
-
+                }               
             });
             result.standard = Math.Round((result.studentIds.Count - result.lostStus.Count) > 0 ? Math.Pow(powSum / (result.studentIds.Count - result.lostStus.Count), 0.5) : 0, 2);
             result.csRate = csRate;

+ 16 - 1
TEAMModelOS/ClientApp/public/lang/en-US.js

@@ -1703,7 +1703,7 @@ const LANG_EN_US = {
             choosed: 'Deselect',
             searchPaper: 'Enter exam file name to search...',
             copyTip1: 'Use ',
-            copyTip2: '  to create a copy'
+            copyTip2: 'Duplicate'
         },
         importFile: {
             uploadSuc: 'Exam file uploaded and parsed successfully!',
@@ -1906,6 +1906,21 @@ const LANG_EN_US = {
     },
     // 首页相关
     home: {
+        clean: {
+            avatar: 'Avatar Data',
+            clean: 'Quick cleanup',
+            title: 'Clean up personal space',
+            type: 'Category',
+            count: 'Quantity',
+            size: 'Occupied space',
+            tip1: 'This function is only used to clean up unused data generated by various activities (such as videos, pictures, activity records, lesson records, question bank and syllabus, etc.), which can free up some space for your IES cloud storage. This operation will not affect your normal activity data on IES. If you want more personal space, you can go to each function to delete some unnecessary records and files or contact the administrator to apply/purchase more space. ',
+            tip2: 'Identify ',
+            tip3: ' unused files, which occupy a total of',
+            tip4: 'No unused data found; no cleanup necessary! ',
+            tip5: 'Rescan',
+            tip6: 'Start scanning',
+            tip7: 'Clean up now'
+        },
         previewStudy: 'Previews before class',
         classData: 'Lesson Data',
         recentRecord: 'Recent 7-day lesson record',

+ 15 - 0
TEAMModelOS/ClientApp/public/lang/zh-CN.js

@@ -1905,6 +1905,21 @@ const LANG_ZH_CN = {
     },
     // 首页相关
     home: {
+        clean: {
+            avatar: '头像数据',
+            clean: '一键清理',
+            title: '清理个人空间',
+            type: '类别',
+            count: '数量',
+            size: '所占空间',
+            tip1: '此功能仅用于清理各类活动产生的音频视频图片、活动数据、课例数据、题目题库课纲等无效或未关联数据,可为您的IES云盘空间腾出部分使用空间。此操作不会影响您在IES上的正常活动数据。如果您想要腾出更大的个人空间,可前往各功能模块删除活动、资源数据或者联系管理员购买更多空间。',
+            tip2: '共扫描出无效文件',
+            tip3: '个,共占用空间',
+            tip4: '未扫描到无效或未关联数据,无需清理!',
+            tip5: '重新扫描',
+            tip6: '开始扫描',
+            tip7: '立即清理'
+        },
         previewStudy: '课前预习',
         classData: '课堂数据',
         recentRecord: '近期课堂记录',

+ 15 - 0
TEAMModelOS/ClientApp/public/lang/zh-TW.js

@@ -1907,6 +1907,21 @@ const LANG_ZH_TW = {
     },
     // 首页相关
     home: {
+        clean: {
+            avatar: '頭像數據',
+            clean: '一鍵清理',
+            title: '清理個人空間',
+            type: '類別',
+            count: '數量',
+            size: '所佔空間',
+            tip1: '此功能僅用於清理各類活動產生的無效或未關聯資料(例如影片、圖片、活動記錄、課堂記錄、題目題庫課綱等),可為您的IES雲端儲存騰出一些空間。此操作不會影響您在IES上的正常活動資料。如果您想要更多的個人空間,可前往各功能去刪除一些不需要的記錄、檔案或者聯絡管理員申請/購買更多空間。 ',
+            tip2: '共掃描出無效檔案',
+            tip3: '個,共佔用空間',
+            tip4: '未掃描到無效或未關聯資料,無需清理! ',
+            tip5: '重新掃描',
+            tip6: '開始掃描',
+            tip7: '立即清理'
+        },
         previewStudy: '課前預習',
         classData: '課堂數據',
         recentRecord: '近期課堂記錄',

+ 8 - 0
TEAMModelOS/ClientApp/src/api/lessonRecord.js

@@ -56,4 +56,12 @@ export default {
     getLessonInfo: function (data) {
         return post("/common/lesson-record/get-lesson-record-id", data)
     },
+    // 扫描个人空间缓存
+    scanUnlink: function (data) {
+        return post("/blob/scan-unlink", data)
+    },
+    // 清理个人空间
+    deleteUnlink: function (data) {
+        return post("/blob/delete-unlink", data)
+    }
 }

+ 1 - 1
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReportCharts/LessonTestReportCharts.vue

@@ -37,7 +37,7 @@
                 </Card>
             </i-col>
         </Row>
-        <Row :gutter="20">
+        <Row :gutter="20" v-show="chartsData.cloudas">
             <!-- 落点图 -->
             <i-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" :xxl="12">
                 <Card style="margin-bottom: 20px;">

+ 4 - 1
TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/PaperViewBox/PaperView.vue

@@ -391,7 +391,8 @@
                                     filed: res.filed,
                                     knowledge: res.knowledge,
                                     total: res.total,
-                                    tableData: subjectScatter
+                                    tableData: subjectScatter,
+                                    cloudas: res.cloudas
                                 }
                                 this.getCorrectData(res)
                                 res.papers.forEach(item => {
@@ -454,6 +455,7 @@
                                         knowledge: this.allCharts.knowledge[0],
                                         total: this.allCharts.total[0],
                                         tableData: this.allCharts.tableData[0],
+                                        cloudas: this.allCharts.cloudas
                                     }
                                     console.log(this.artExam.length);
                                     // 艺术评测需要acId,这里将原本的paper增加一个acId
@@ -575,6 +577,7 @@
                             knowledge: this.allCharts.knowledge[index],
                             total: this.allCharts.total[index],
                             tableData: this.allCharts.tableData[index],
+                            cloudas: this.allCharts.cloudas
                         }
                         this.getPaper(item)
                     }

+ 6 - 3
TEAMModelOS/ClientApp/src/components/student-web/WrongQusetion/WrongQues.vue

@@ -22,7 +22,8 @@
             </div>
             <div>
                 <p class="count-text">{{ $t("studentWeb.wrongQues.summary5") }}</p>
-                <p class="count-text-foot">
+                <p class="count-text-foot count-num count-num-4" v-if="lastTime.day < 0">{{ '今日' }}</p>
+                <p class="count-text-foot" v-else>
                     <span class="count-num count-num-4">{{ lastTime.day }}</span>
                     {{ $t("studentWeb.wrongQues.day1") }}
                     <span>({{ lastTime.time }})</span>
@@ -171,13 +172,15 @@ export default {
                     if(type) {
                         if(res.data.length) {
                             let nowTime = new Date().getTime()
+                            let startTime = new Date(new Date().toLocaleDateString()).getTime()
+                            let endTime = new Date(new Date().toLocaleDateString()).getTime() + 24*60*60*1000 - 1
                             this.lastTime = {
                                 time: res.data[0].last_rev_time ? this.dateFormat(res.data[0].last_rev_time) : '-',
-                                day: Math.floor((nowTime - res.data[0].last_rev_time) / (1000*60*60*24))
+                                day: res.data[0].last_rev_time > startTime && res.data[0].last_rev_time < endTime ? -1 : Math.floor((nowTime - res.data[0].last_rev_time) / (1000*60*60*24))
                             }
                             this.nextTime = {
                                 time: res.data[0].nxt_rev_time ? this.dateFormat(res.data[0].nxt_rev_time) : '-',
-                                day: Math.floor((res.data[0].nxt_rev_time - nowTime) / (1000*60*60*24))
+                                day: res.data[0].nxt_rev_time > startTime && res.data[0].nxt_rev_time < endTime ? -1 : Math.floor((res.data[0].nxt_rev_time - startTime) / (1000*60*60*24))
                             }
                             this.topicTotal = res.data[0].total_qs
                             this.wellDone = res.data[0].well_done_qs

+ 6 - 0
TEAMModelOS/ClientApp/src/css/common-style.less

@@ -233,6 +233,8 @@
     top: 60px;
 }
 
+
+
 //修改名称对话框
 .ed-name-modal .ivu-modal-header {
     border-bottom: none;
@@ -254,6 +256,10 @@
     }
 }
 
+.clean-modal .ivu-modal-header {
+    padding: 30px 25px 5px 25px;
+}
+
 .edit-name-content {
     padding: 0px 30px;
 

+ 32 - 0
TEAMModelOS/ClientApp/src/view/homepage/HomePage.less

@@ -16,6 +16,35 @@
     background: #f2f2f2;
     padding: 10px 0px 10px 10px;
 }
+.scan-result {
+    padding: 10px;
+    font-size: 14px;
+    max-height: 400px;
+    overflow: auto;
+    margin-bottom: 20px;
+
+    .scan-item {
+        display: flex;
+        margin: 15px 0;
+
+        .type {
+            width: 100px;
+        }
+
+        .count {
+            margin-left: 50px;
+            width: 100px;
+            text-align: center;
+        }
+
+        .size {
+            margin-left: 100px;
+            width: 100px;
+            text-align: center;
+        }
+    }
+}
+
 .chart-box{
     width: ~"calc(100% - 335px)";
     float: left;
@@ -77,6 +106,9 @@
     position: absolute;
     left: 20px;
     top: 20px;
+    width: 90%;
+    display: flex;
+    justify-content: space-between;
 }
 @media screen and (max-width: 1400px){
     .train-chart-box{

Fichier diff supprimé car celui-ci est trop grand
+ 726 - 414
TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue


+ 0 - 1
TEAMModelOS/ClientApp/src/view/homepage/SpaceInfo.vue

@@ -87,7 +87,6 @@ export default {
   methods: {
     // 获取容器空间情况 
     getSize() {
-      console.error('xxxxxxxxxxxxxxxxxxxx')
       BlobTool.getContainerSize(this.$store.state.userInfo.TEAMModelId, 'private').then(
         res => {
           console.log(res)

+ 2 - 2
TEAMModelOS/Controllers/Common/ExamController.cs

@@ -1878,10 +1878,10 @@ namespace TEAMModelOS.Controllers
                         var knowledge = know.Select(k => new { k.kn, k.kps, k.ckps, k.akps });
                         var filed = fp.Select(k => new { k.fs, k.fps, k.cfps, k.afps });
                         //papers = papers
-                        return Ok(new { info.papers, subjects, stuScore, stuAns, mark, total, claId = infoIds, knowledge, filed, average, wno, subjectScatter, status = 200 });
+                        return Ok(new { info.cloudas,info.papers, subjects, stuScore, stuAns, mark, total, claId = infoIds, knowledge, filed, average, wno, subjectScatter, status = 200 });
                     }
                 }
-                return Ok(new { info.papers, subjects, stuScore, stuAns, mark, total, claId = infoIds, knowledge = new List<object>(), filed = new List<object>(), average, wno, subjectScatter, status = 200 });
+                return Ok(new { info.cloudas,info.papers, subjects, stuScore, stuAns, mark, total, claId = infoIds, knowledge = new List<object>(), filed = new List<object>(), average, wno, subjectScatter, status = 200 });
             }
             catch (Exception ex)
             {

+ 106 - 13
TEAMModelOS/Controllers/System/BlobController.cs

@@ -33,6 +33,9 @@ using ContentTypeDict = TEAMModelOS.SDK.ContentTypeDict;
 using TEAMModelOS.SDK.Services;
 using DocumentFormat.OpenXml.Wordprocessing;
 using OpenXmlPowerTools;
+using Azure.Storage.Blobs;
+using Azure.Storage.Blobs.Specialized;
+using DocumentFormat.OpenXml.Drawing.Wordprocessing;
 
 namespace TEAMModelOS.Controllers
 {
@@ -852,20 +855,98 @@ namespace TEAMModelOS.Controllers
         [AuthToken(Roles = "teacher,admin")]
         [HttpPost("delete-unlink")]
         public async Task<IActionResult> DeleteUnlink(JsonElement json) {
-            var (userid, _, _, school) = HttpContext.GetAuthTokenInfo();
-            int status = 0;
-            if (!json.TryGetProperty("scope", out JsonElement scope))
-            {
-                return Ok(new { status, msg = "参数错误" });
-            }
-            string containerName = scope.ToString().Equals("school", StringComparison.OrdinalIgnoreCase) ? school : userid;
-            bool exists = await _azureRedis.GetRedisClient(8).KeyExistsAsync($"Blob:ScanResult:{scope}:{containerName}");
-            if (exists)
-            {
-                return Ok(new { status = 2, msg = "暂无清理项!" });
+            try {
+                var (userid, _, _, school) = HttpContext.GetAuthTokenInfo();
+                int status = 0;
+                if (!json.TryGetProperty("scope", out JsonElement scope))
+                {
+                    return Ok(new { status, msg = "参数错误" });
+                }
+                string containerName = scope.ToString().Equals("school", StringComparison.OrdinalIgnoreCase) ? school : userid;
+                bool exists = await _azureRedis.GetRedisClient(8).KeyExistsAsync($"Blob:ScanResult:{scope}:{containerName}");
+                if (exists)
+                {
+                    var result = await _azureRedis.GetRedisClient(8).StringGetAsync($"Blob:ScanResult:{scope}:{containerName}");
+                    if (result.HasValue)
+                    {
+                        List<UnLink> unLinksData = result.ToString().ToObject<List<UnLink>>();
+                        if (unLinksData.IsNotEmpty())
+                        {
+                            var uri = _azureStorage.GetBlobContainerClient(containerName).Uri;
+                            BlobBatchClient blobBatch = _azureStorage.GetBlobContainerClient(containerName).GetBlobBatchClient();
+                            foreach (var unLink in unLinksData)
+                            {
+
+                                var urls =  unLink.blobs.Select(z => z.Key).Select(z =>  new Uri(Path.Combine(uri.ToString(), z)));
+
+                                int len = 100;
+                                if (urls.Count() > 0)
+                                {
+                                    if (urls.Count() <= len)
+                                    {
+                                        try
+                                        {
+                                            await blobBatch.DeleteBlobsAsync(urls);
+                                        }
+                                        catch (Exception ex) { }
+                                    }
+                                    else
+                                    {
+                                        int pages = (urls.Count() + len) / len; //256是批量操作最大值,pages = (total + max -1) / max;
+                                        for (int i = 0; i < pages; i++)
+                                        {
+                                            List<Uri> lists = urls.Skip((i) * len).Take(len).ToList();
+                                            try
+                                            {
+                                                await blobBatch.DeleteBlobsAsync(lists);
+                                            }
+                                            catch (Exception ex) { }
+                                        }
+                                    }
+                                }
+                            }
+                            //为节省服务器开销, 限制只能一天清理一次
+#if DEBUG
+                            _azureRedis.GetRedisClient(8).StringSet($"Blob:ScanResult:{scope}:{containerName}", new List<UnLink>().ToJsonString(), expiry: new TimeSpan(0, 0, 30));
+#else
+                        _azureRedis.GetRedisClient(8).StringSet($"Blob:ScanResult:{scope}:{containerName}", new List<UnLink>().ToJsonString(), expiry: new TimeSpan(24, 0, 0));
+#endif
+                            HashSet<string> root = null;
+                            if (_option.Location.Contains("Test", StringComparison.OrdinalIgnoreCase) || _option.Location.Contains("Dep", StringComparison.OrdinalIgnoreCase))
+                            {
+                                root = unLinksData.Select(x => x.prefix).ToHashSet();
+                            }
+                            else
+                            {
+                                root = unLinksData.Where(z => z.size > 0).Select(x => x.prefix).ToHashSet();
+                            }
+                            if (root != null)
+                            {
+                                root.ToList().ForEach(async x => {
+                                    await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "update", root = x, name = $"{containerName}" }, _serviceBus, _configuration, _azureRedis);
+                                });
+                            }
+                            return Ok(new { status = 3, msg = "清理成功!" });
+                        }
+                        else
+                        {
+                            return Ok(new { status = 2, msg = "最近清理过,暂无清理项!" });
+                        }
+                    }
+                    else
+                    {
+                        return Ok(new { status = 2, msg = "最近清理过,暂无清理项!" });
+                    }
+                }
+                else
+                {
+                    return Ok(new { status = 4, msg = "请重新检查清理项!" });
+                }
+            } catch (Exception ex ) {
+              await  _dingDing.SendBotMsg($"{_option.Location},{DeleteUnlink}\n{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
             }
+            return Ok(new { status = 4, msg = "请重新检查清理项!" });
 
-            return Ok(new { status, msg = "暂无清理项!" });
         }
         [ProducesDefaultResponseType]
         [Authorize(Roles = "IES")]
@@ -880,6 +961,9 @@ namespace TEAMModelOS.Controllers
                 return Ok(new { status, msg = "参数错误" });
             }
             string containerName = scope.ToString().Equals("school", StringComparison.OrdinalIgnoreCase) ? school : userid;
+            if (string.IsNullOrWhiteSpace(containerName)) {
+                return Ok(new { status, msg = "参数错误" });
+            }
             bool exists = await _azureRedis.GetRedisClient(8).KeyExistsAsync($"Blob:ScanResult:{scope}:{containerName}");
             if (exists)
             {
@@ -948,6 +1032,10 @@ namespace TEAMModelOS.Controllers
                                     long? size = unlink.Select(z => z.Value).Sum();
                                     unLinks.Add(new UnLink { prefix = prefix, blobs = unlink, size = size });
                                 }
+                                else {
+                                    long? size = blobs.Select(z => z.Value).Sum();
+                                    unLinks.Add(new UnLink { prefix = prefix, blobs = blobs, size = size });
+                                }
                             }
                             break;
                         }
@@ -1261,7 +1349,12 @@ namespace TEAMModelOS.Controllers
                 summary.Add(new { prefix = x.Key, count = count, size = size });
             });
             //为节省服务器开销, 限制只能一天清理一次
-            _azureRedis.GetRedisClient(8).StringSet($"Blob:ScanResult:{scope}:{containerName}", unLinks.ToJsonString(), expiry: new TimeSpan(24, 0, 0));
+#if DEBUG
+            _azureRedis.GetRedisClient(8).StringSet($"Blob:ScanResult:{scope}:{containerName}", unLinks.ToJsonString(), expiry: new TimeSpan(0, 0,30));
+#else
+             _azureRedis.GetRedisClient(8).StringSet($"Blob:ScanResult:{scope}:{containerName}", unLinks.ToJsonString(), expiry: new TimeSpan(24, 0, 0));
+#endif
+
             return Ok(new { status = 1, totalCount, totalSize, summary, unLinks });
         }
     }

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

@@ -4,6 +4,7 @@ using Azure.Cosmos;
 using Azure.Messaging.ServiceBus;
 using Azure.Storage.Blobs;
 using Azure.Storage.Blobs.Models;
+using Azure.Storage.Blobs.Specialized;
 using DinkToPdf;
 using DinkToPdf.Contracts;
 using DocumentFormat.OpenXml.Drawing.Wordprocessing;
@@ -87,8 +88,7 @@ namespace TEAMModelOS.Controllers
             _searcher = searcher;
         }
 
-       
-
+        
         /// <summary>
         /// 
         /// </summary>

+ 4 - 4
TEAMModelOS/TEAMModelOS.csproj

@@ -69,11 +69,11 @@
     <SpaRoot>ClientApp\</SpaRoot>
     <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
     <UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-    <Version>5.2306.14</Version>
-    <AssemblyVersion>5.2306.14.1</AssemblyVersion>
-    <FileVersion>5.2306.14.1</FileVersion>
+    <Version>5.2306.20</Version>
+    <AssemblyVersion>5.2306.20.1</AssemblyVersion>
+    <FileVersion>5.2306.20.1</FileVersion>
     <Description>TEAMModelOS(IES5)</Description>
-    <PackageReleaseNotes>IES版本说明版本切换标记5.2306.14.1</PackageReleaseNotes>
+    <PackageReleaseNotes>IES版本说明版本切换标记5.2306.20.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.2306.14.1"
+    "Version": "5.2306.20.1"
   },
   "Azure": {
     // 测试站数据库

+ 1 - 1
TEAMModelOS/appsettings.json

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