浏览代码

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

zhouj1203@hotmail.com 2 年之前
父节点
当前提交
bde7b4f9e3
共有 47 个文件被更改,包括 1188 次插入590 次删除
  1. 5 5
      TEAMModelAPI/Controllers/Business/CourseController.cs
  2. 1 1
      TEAMModelAPI/Controllers/Business/ExamController.cs
  3. 8 8
      TEAMModelAPI/Controllers/Business/GroupListController.cs
  4. 3 3
      TEAMModelAPI/Controllers/Business/RoomController.cs
  5. 2 2
      TEAMModelAPI/Controllers/Business/SchoolController.cs
  6. 1 1
      TEAMModelBI/ClientApp/public/index.html
  7. 4 0
      TEAMModelBI/ClientApp/src/api/index.js
  8. 12 8
      TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue
  9. 15 3
      TEAMModelBI/ClientApp/src/view/created/created.vue
  10. 62 5
      TEAMModelBI/ClientApp/src/view/participation/examination.vue
  11. 2 2
      TEAMModelBI/ClientApp/src/view/participation/index.vue
  12. 288 0
      TEAMModelBI/ClientApp/src/view/participation/paper.vue
  13. 5 5
      TEAMModelBI/ClientApp/src/view/schoolServe/school.vue
  14. 2 2
      TEAMModelBI/ClientApp/src/view/teachermanage/school.vue
  15. 10 2
      TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs
  16. 2 0
      TEAMModelOS.SDK/Models/Cosmos/Common/GroupList.cs
  17. 2 2
      TEAMModelOS.SDK/Models/Cosmos/Common/LessonRecord.cs
  18. 77 31
      TEAMModelOS.SDK/Models/Service/GroupListService.cs
  19. 58 0
      TEAMModelOS.SDK/Models/Service/SchoolService.cs
  20. 1 1
      TEAMModelOS.SDK/Models/Service/StudentService.cs
  21. 0 6
      TEAMModelOS.sln
  22. 6 1
      TEAMModelOS/ClientApp/public/lang/en-US.js
  23. 9 4
      TEAMModelOS/ClientApp/public/lang/zh-CN.js
  24. 23 18
      TEAMModelOS/ClientApp/public/lang/zh-TW.js
  25. 25 22
      TEAMModelOS/ClientApp/src/api/lessonRecord.js
  26. 21 7
      TEAMModelOS/ClientApp/src/common/BaseLayout.vue
  27. 1 1
      TEAMModelOS/ClientApp/src/components/research-dashboard/BaseTechBar.vue
  28. 14 24
      TEAMModelOS/ClientApp/src/components/research-dashboard/LeftTop.vue
  29. 5 5
      TEAMModelOS/ClientApp/src/router/routes.js
  30. 2 2
      TEAMModelOS/ClientApp/src/view/artexam/Mgt.vue
  31. 286 286
      TEAMModelOS/ClientApp/src/view/auth/ProdRecord.vue
  32. 2 2
      TEAMModelOS/ClientApp/src/view/dashboard/Research.less
  33. 1 1
      TEAMModelOS/ClientApp/src/view/dashboard/Research.vue
  34. 1 1
      TEAMModelOS/ClientApp/src/view/dashboard/Student.vue
  35. 1 1
      TEAMModelOS/ClientApp/src/view/dashboard/StudentAll.vue
  36. 1 1
      TEAMModelOS/ClientApp/src/view/dashboard/fiveEdu/FiveEdu.less
  37. 1 1
      TEAMModelOS/ClientApp/src/view/dashboard/fiveEdu/FiveEdu.vue
  38. 1 1
      TEAMModelOS/ClientApp/src/view/dashboard/style.less
  39. 56 4
      TEAMModelOS/ClientApp/src/view/research-center/ResearchMgt.less
  40. 129 108
      TEAMModelOS/ClientApp/src/view/research-center/ResearchMgt.vue
  41. 2 1
      TEAMModelOS/ClientApp/src/view/student-account/stulist/MgtStuList.vue
  42. 5 3
      TEAMModelOS/ClientApp/src/view/teachermgmt/components/mgt/TeacherMgt.vue
  43. 5 2
      TEAMModelOS/Controllers/Both/GroupListController.cs
  44. 5 2
      TEAMModelOS/Controllers/OpenApi/OpenSchool/ScGroupListController.cs
  45. 1 1
      TEAMModelOS/Controllers/School/ArtReviewController.cs
  46. 21 0
      TEAMModelOS/Controllers/XTest/FixLessonRecordController.cs
  47. 4 4
      TEAMModelOS/TEAMModelOS.csproj

+ 5 - 5
TEAMModelAPI/Controllers/Business/CourseController.cs

@@ -58,7 +58,7 @@ namespace TEAMModelAPI.Controllers
         }
         [ProducesDefaultResponseType]
         [HttpPost("get-course-list")]
-        [ApiToken(Auth = "1301", Name = "获取课程列表信息", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1301", Name = "获取课程列表信息", RWN = "R", Limit = false)]
         public async Task<IActionResult> GetCourseList(JsonElement json)
         {
             var client = _azureCosmos.GetCosmosClient();
@@ -85,7 +85,7 @@ namespace TEAMModelAPI.Controllers
 
         [ProducesDefaultResponseType]
         [HttpPost("get-course-info")]
-        [ApiToken(Auth = "1302", Name = "课程详细信息", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1302", Name = "课程详细信息", RWN = "R", Limit = false)]
         public async Task<IActionResult> GetCourseInfo(JsonElement json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -111,7 +111,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-period-timetable")]
-        [ApiToken(Auth = "1303", Name = "试卷和评测的条件信息", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1303", Name = "试卷和评测的条件信息", RWN = "R", Limit = false)]
         public async Task<IActionResult> GetPaperExamCondition(JsonElement json)
         {
             json.TryGetProperty("periodId", out JsonElement _periodId);
@@ -132,7 +132,7 @@ namespace TEAMModelAPI.Controllers
 
         [ProducesDefaultResponseType]
         [HttpPost("upsert-course-infos")]
-        [ApiToken(Auth = "1304", Name = "课程详细信息", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1304", Name = "课程详细信息", RWN = "W", Limit = false)]
         public async Task<IActionResult> UpsertCourseInfo(CourseDtoImpt json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -244,7 +244,7 @@ namespace TEAMModelAPI.Controllers
         
         [ProducesDefaultResponseType]
         [HttpPost("upsert-course-schedule")]
-        [ApiToken(Auth = "1305", Name = "更新课程的排课信息", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1305", Name = "更新课程的排课信息", RWN = "W", Limit = false)]
         public async Task<IActionResult> UpsertCourseSchedule(ImportCourseDto json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();

+ 1 - 1
TEAMModelAPI/Controllers/Business/ExamController.cs

@@ -60,7 +60,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-paper-exam-condition")]
-        [ApiToken(Auth = "1101", Name = "试卷和评测的条件信息", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1101", Name = "试卷和评测的条件信息", RWN = "R", Limit = false)]
         public async Task<IActionResult> GetPaperExamCondition(JsonElement json)
         {
             json.TryGetProperty("periodId", out JsonElement _periodId);

+ 8 - 8
TEAMModelAPI/Controllers/Business/GroupListController.cs

@@ -63,7 +63,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-group-list")]
-        [ApiToken(Auth = "1201", Name = "学校名单列表", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1201", Name = "学校名单列表", RWN = "R", Limit = false)]
         public async Task<IActionResult> GetGroupList(JsonElement json)
         {
             var client = _azureCosmos.GetCosmosClient();
@@ -159,7 +159,7 @@ namespace TEAMModelAPI.Controllers
         }
         [ProducesDefaultResponseType]
         [HttpPost("get-group-members")]
-        [ApiToken(Auth = "1202", Name = "获取名单详细信息和成员信息", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1202", Name = "获取名单详细信息和成员信息", RWN = "R", Limit = false)]
         public async Task<IActionResult> GetGroupMembers(JsonElement json)
         {
             var client = _azureCosmos.GetCosmosClient();
@@ -176,7 +176,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("import-class-members")]
-        [ApiToken(Auth = "1203", Name = "导入行政班学生", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1203", Name = "导入行政班学生", RWN = "W", Limit = false)]
         public async Task<IActionResult> ImportClassMembers(JsonElement json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -211,7 +211,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("update-class-members")]
-        [ApiToken(Auth = "1204", Name = "更新行政班学生", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1204", Name = "更新行政班学生", RWN = "W", Limit = false)]
         public async Task<IActionResult> UpdateClassMembers(JsonElement json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -248,7 +248,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("remove-class-members")]
-        [ApiToken(Auth = "1205", Name = "移除行政班学生", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1205", Name = "移除行政班学生", RWN = "W", Limit = false)]
         public async Task<IActionResult> RemoveClassMembers(JsonElement json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -290,7 +290,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("upsert-teach-groups")]
-        [ApiToken(Auth = "1206", Name = "创建或更新教学班", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1206", Name = "创建或更新教学班", RWN = "W", Limit = false)]
         public async Task<IActionResult> UpsertTeachGroups(GroupListDtoImpt json) {
             var (_, school) = HttpContext.GetApiTokenInfo();
             var groupListsDto = json.groupLists;
@@ -378,7 +378,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("import-teach-members")]
-        [ApiToken(Auth = "1207", Name = "导入教学班学生", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1207", Name = "导入教学班学生", RWN    = "W", Limit = false)]
         public async Task<IActionResult> ImportTeachMembers(MemberImpt json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -447,7 +447,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("remove-teach-members")]
-        [ApiToken(Auth = "1208", Name = "移除教学班学生", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1208", Name = "移除教学班学生", RWN = "W", Limit = false)]
         public async Task<IActionResult> RemoveTeachMembers(JsonElement json) {
             var (id, school) = HttpContext.GetApiTokenInfo();
             json.TryGetProperty("stuids", out JsonElement _stuids);

+ 3 - 3
TEAMModelAPI/Controllers/Business/RoomController.cs

@@ -57,7 +57,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-room-list")]
-        [ApiToken(Auth = "1401", Name = "获取物理教室列表", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1401", Name = "获取物理教室列表", RWN= "R", Limit = false)]
         public async Task<IActionResult> GetRoomList(JsonElement json)
         {
             var client = _azureCosmos.GetCosmosClient();
@@ -88,7 +88,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-room-info")]
-        [ApiToken(Auth = "1402", Name = "获取物理教室详细信息", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1402", Name = "获取物理教室详细信息", RWN= "R", Limit = false)]
         public async Task<IActionResult> GetRoomInfo(JsonElement json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();
@@ -120,7 +120,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("upsert-room-infos")]
-        [ApiToken(Auth = "1403", Name = "创建或更新教学班", RW = "W", Limit = false)]
+        [ApiToken(Auth = "1403", Name = "创建或更新教学班", RWN= "W", Limit = false)]
         public async Task<IActionResult> UpsertRoomInfo(RoomsDto json)
         {
             var (id, school) = HttpContext.GetApiTokenInfo();

+ 2 - 2
TEAMModelAPI/Controllers/Business/SchoolController.cs

@@ -59,7 +59,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-schools")]
-        [ApiToken(Auth = "1000", Name = "合作商获取可访问的学校列表", RW = "R", Limit = false)]
+        [ApiToken(Auth = "1000", Name = "合作商获取可访问的学校列表", RWN= "R", Limit = false)]
         public async Task<IActionResult> GetSchools() {
             var (id, _) = HttpContext.GetApiTokenInfo();
             var table = _azureStorage.GetCloudTableClient().GetTableReference("IESOpenApi");
@@ -73,7 +73,7 @@ namespace TEAMModelAPI.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-school-info")]
-        [ApiToken(Auth = "1001",Name = "学校基础信息", RW = "R", Limit =false)]
+        [ApiToken(Auth = "1001",Name = "学校基础信息", RWN= "R", Limit =false)]
         public async Task<IActionResult> GetSchoolInfo()
         {
             var (id, school) = HttpContext.GetApiTokenInfo();

+ 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_jpe031zj2cg.js"></script>
+<script src="https://at.alicdn.com/t/c/font_2934132_2ayfnivoa9y.js"></script>
 <script src="../src/access/iconfont.js"></script>
 
 <body>

+ 4 - 0
TEAMModelBI/ClientApp/src/api/index.js

@@ -413,6 +413,10 @@ export default {
     getSchoolsas(data) {
         return post('/biservers/get-cntrkey', data)
     },
+    //访问试卷信息
+    getExamintionpaper(url) {
+        return fetch(url, '')
+    },
 
     //第三方相关API(BI)
     //创建or保存 第三方信息

+ 12 - 8
TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue

@@ -1066,14 +1066,18 @@ export default {
       proxy.$api.areaAddadmins(data).then((res) => {
         // res.state === 200 ? (ElMessage.success('操作成功'), getAreasadmin()) : ''
         if (res.state === 200 || res.state === 201) {
-          if (res.existsArea !== null) {
-            ElMessage.warning('该管理员已是本学区管理员,请勿重复添加')
-          } else if (res.existsSc.length !== 0) {
-            ElMessage.success('操作成功')
-            stageShow.value.state = false
-            getAreasadmin()
-          } else if (res.errorSc.length !== 0) {
-            ElMessage.error('全部或部分设置学校管理员操作失败')
+          if (res.hasOwnProperty('existsArea')) {
+            if (res.existsArea !== null) {
+              ElMessage.warning('该管理员已是本学区管理员,请勿重复添加')
+            } else if (res.existsSc.length !== 0) {
+              ElMessage.success('操作成功')
+              stageShow.value.state = false
+              getAreasadmin()
+            } else if (res.errorSc.length !== 0) {
+              ElMessage.error('全部或部分设置学校管理员操作失败')
+            }
+          } else {
+            res.state === 200 ? (ElMessage.success('操作成功'), stageShow.value.state = false, getAreasadmin()) : res.state === 201 ? (ElMessage.success('部分学校操作成功'), stageShow.value.state = false, getAreasadmin()) : ''
           }
         }
       }).catch((error) => {

+ 15 - 3
TEAMModelBI/ClientApp/src/view/created/created.vue

@@ -1518,19 +1518,31 @@ export default {
       console.log(value, '即将回报的学校')
       let regionsJosn = siteValue === 'cn' ? option_cn : option_gl
       let periodData = [
+        { label: '学前', value: '11' },
         { label: '小学', value: '21' },
         { label: '初中', value: '31' },
         { label: '高中', value: '34' },
-        { label: '职高', value: '36' },
-        { label: '大学', value: '41' },
+        { label: '中职(中专,技校,职高)', value: '36' },
+        { label: '大学本科', value: '41' },
+        { label: '高职(专科)', value: '44' },
+        { label: '特殊教育', value: '51' },
+        { label: '教育局', value: '91' },
+        { label: '电教部门', value: '51' },
+        { label: '成人中专', value: '33' },
+        { label: '成人高教', value: '42' },
+        { label: '硕士研究生', value: '41' },
+        { label: '博士研究生', value: '41' },
+        { label: '企业', value: '99' },
       ]
       let periodValue = []
       for (let i in value[0].period) {
-        let name = value[0].period[i]
+        let name = value[0].period[i].name
         for (let n in periodData) {
           periodData[n].label === name ? periodValue.push(periodData[n].value) : ''
         }
       }
+      // periodValue = Array.from(new Set(periodValue))
+      periodValue = [...new Set(periodValue)]
       //省 关键字剔除
       let textNums = value[0].province.indexOf('省') !== -1 ? value[0].province.indexOf('省') : value[0].province.indexOf('自治区') !== -1 ? value[0].province.indexOf('自治区') : value[0].province.indexOf('市') !== -1 ? value[0].province.indexOf('市') : value[0].province.indexOf('特别行政区') !== -1 ? value[0].province.indexOf('特别行政区') : ''
       let provinceText = value[0].province.substr(0, textNums)

+ 62 - 5
TEAMModelBI/ClientApp/src/view/participation/examination.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="examinationbox">
+  <div class="examinationbox" v-if="uistate ==='default'">
     <div class="header-filter">
       <el-collapse v-model="activeNames" accordion>
         <el-collapse-item title="数据筛选" name="1">
@@ -108,20 +108,31 @@
       </div>
     </div>
   </div>
+  <div v-else-if="uistate ==='details'">
+    <Paper @renew="backdefaults" :paperInfo="paperInfo"></Paper>
+  </div>
 </template>
 <script>
 import { ref, watch, getCurrentInstance } from 'vue'
 import { useStore } from 'vuex'
 import { ElMessage, ElLoading } from 'element-plus'
+import { useRouter } from 'vue-router'
+import BlobTool from '@/until/blobTool.js'
+import Paper from './paper.vue'
 export default {
   props: {
     detailsSchool: {
       default: {}
     },
   },
+  components: {
+    Paper
+  },
   setup (props) {
     let { proxy } = getCurrentInstance()
     const store = useStore()
+    let router = useRouter()
+    let uistate = ref('default')
     let activeNames = ref(['1'])
     const notdataImg = require('@/assets/img/notdata.png')
     let findbox = ref({
@@ -166,6 +177,13 @@ export default {
       data: [],
       nowselectData: []
     })
+    //试卷相关信息
+    let paperInfo = ref({
+      total: 0,
+      title: '',
+      difficulty: 0,
+      list: [],
+    })
     //blob相关
     let blobData = ref({
       osblob_uri: '',
@@ -289,11 +307,22 @@ export default {
       console.log(blobData.value, '现在去获取')
       let paths = value.blob + '/index.json'
       // let space = bolbs.osblob_uri.slice(bolbs.osblob_uri.indexOf('cn') + 3)
-      let urls = blobData.value.osblob_uri + paths + '?' + blobData.value.osblob_sas
+      let urls = paths
       // console.log(bolbs, host, space, '参数')
       console.log(urls, '-------------', '拼接内容')
-
-      // proxy.Blob.downloadToFile()
+      console.log(proxy.Blob, '原型挂载')
+      let urlheader = blobData.value.osblob_uri.substring(0, blobData.value.osblob_uri.indexOf('cn') + 2)
+      let space = blobData.value.osblob_uri.slice(blobData.value.osblob_uri.indexOf('cn') + 3)
+      console.log(urlheader, space, blobData.value.osblob_sas, '内容')
+      // let Blobs = new BlobTool(urlheader, space, '?' + blobData.value.osblob_sas, 'school')
+      // // urls = urls.slice(1)
+      // console.log(Blobs, urls, 'blob初始化')
+      proxy.$api.getExamintionpaper(blobData.value.osblob_uri + urls + '?' + blobData.value.osblob_sas).then(async (res) => {
+        console.log(res, '完整的试卷信息')
+        res.hasOwnProperty('slides') ? (await questions(res.slides, value.blob, res.name, res.score)) : ''
+      })
+      uistate.value = 'details'
+      // router.push('/home/paperDetails')
     }
     //获取相应学校的sas
     async function getSas () {
@@ -308,6 +337,30 @@ export default {
         ElMessage.error('获取试卷信息失败,API异常')
       })
     }
+    //获取试题
+    async function questions (slider, blob, name, score) {
+      console.log(slider, blob, '调用到了')
+      let difficultyNum = 0
+      let listdata = []
+      for (let i of slider) {
+        console.log(blobData.value.osblob_uri + blob + '/' + i.url + '?' + blobData.value.osblob_sas, '访问的地址')
+        await proxy.$api.getExamintionpaper(blobData.value.osblob_uri + blob + '/' + i.url + '?' + blobData.value.osblob_sas).then((res) => {
+          console.log(res, res.exercise.level, '试题')
+          difficultyNum += res.exercise.level
+          listdata.push(res)
+        })
+      }
+      // paperInfo.value.difficulty = (difficultyNum / paperData.value.data.length).toFixed(0)
+      // console.log(difficultyNum, paperInfo.value.list.length)
+      paperInfo.value.list = listdata
+      paperInfo.value.title = name
+      paperInfo.value.total = score
+      paperInfo.value.difficulty = (difficultyNum / paperInfo.value.list.length).toFixed(0)
+      console.log(paperInfo.value, '试卷完整信息')
+    }
+    function backdefaults (val) {
+      uistate.value = val
+    }
     watch(
       props,
       (newdata, olddata) => {
@@ -338,7 +391,11 @@ export default {
       getExamblob,
       getBlobHost,
       getSas,
-      blobData
+      blobData,
+      questions,
+      uistate,
+      backdefaults,
+      paperInfo
     }
   },
 }

+ 2 - 2
TEAMModelBI/ClientApp/src/view/participation/index.vue

@@ -251,9 +251,9 @@
       <el-tab-pane :label="$t(`schoolManages.redactGrading`)">
         <SetSchool :detailsSchool="detailsSchool" ref="setSchoolData"></SetSchool>
       </el-tab-pane>
-      <el-tab-pane label="试卷资源">
+      <!-- <el-tab-pane label="试卷资源">
         <Exammination :detailsSchool="detailsSchool"></Exammination>
-      </el-tab-pane>
+      </el-tab-pane> -->
     </el-tabs>
   </div>
   <!--编辑学校页面end-->

+ 288 - 0
TEAMModelBI/ClientApp/src/view/participation/paper.vue

@@ -0,0 +1,288 @@
+<template>
+  <div class="paperbox">
+    <!--试卷信息 难度总分-->
+    <div class="paperbox-header">
+      <div class="header-info">
+        <div class="header-info-items">
+          <div class="header-info-title">总分:<span class="header-info-num">{{paperdata.totalnum}}</span>分</div>
+          <div class="header-info-title">题目数:<span class="header-info-num">{{paperdata.paperList.length}}</span></div>
+          <div class="header-info-title difficulty">难度:
+            <el-rate v-model="paperdata.difficulty" disabled />
+          </div>
+        </div>
+        <div class="header-info-operate">
+          <div>
+            <el-button type="primary" size="small" @click="backDefault">返回列表</el-button>
+          </div>
+          <div>
+            <el-button type="primary" size="small">全部展开</el-button>
+          </div>
+          <div>
+            <el-button type="primary" size="small">拷贝当前试卷</el-button>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="paper-name">{{paperdata.title}}</div>
+    <div class="paper-view">
+      <div>
+        <p class="paper-view-title"><span>一、</span><span>单选题</span><span class="aggregate">(共 1 题,总计 10 分)</span></p>
+        <div class="problem">
+          <!--题目-->
+          <div class="problem-details">
+            <div class="problem-num">1:</div>
+            <div class="problem-content" v-html="paper"></div>
+          </div>
+          <!--题目end-->
+          <!--分数-->
+          <div class="numshow">
+            <div class="numshow-nums"><span>10 分</span></div>
+            <div class="numshow-icon">
+              <div class="numshow-icon-item">
+                <svg class="tagicons" aria-hidden="true" @click="unfold('1')">
+                  <use :xlink:href="shows ? '#icon-shouhuishangxia':'#icon-moduanzhankai_o'"></use>
+                </svg>
+              </div>
+            </div>
+          </div>
+          <!--分数end-->
+          <!--选项-->
+          <div class="proble-single">
+            <div class="item-single">
+              <div class="item-single-tag">A:</div>
+              <div class="item-single-content">123456</div>
+            </div>
+            <div class="item-single">
+              <div class="item-single-tag">B:</div>
+              <div class="item-single-content">154323456</div>
+            </div>
+            <div class="item-single">
+              <div class="item-single-tag">C:</div>
+              <div class="item-single-content">123534534456</div>
+            </div>
+            <div class="item-single">
+              <div class="item-single-tag">D:</div>
+              <div class="item-single-content">123453543456</div>
+            </div>
+          </div>
+          <!--选项end-->
+          <!--展开内容-->
+          <div :class="[unfoldnum == 1 ? 'unfoldIndex':'','spreadbox']">
+            <p><span class="spreadbox-title">【题型】</span><span>单选题</span></p>
+            <p><span class="spreadbox-title">【答案】</span><span>D</span></p>
+            <p><span class="spreadbox-title">【解析】</span><span>不等式</span></p>
+            <p><span class="spreadbox-title">【知识点】</span><span> 不等式计算</span></p>
+            <p><span class="spreadbox-title">【认知层次】</span><span>应用</span></p>
+            <p><span class="spreadbox-title">【补救资源】</span><span>暂无</span></p>
+          </div>
+          <!--展开内容end-->
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import { ref, watch, getCurrentInstance } from 'vue'
+import { useStore } from 'vuex'
+export default ({
+  props: {
+    paperInfo: {
+      type: Object,
+      default: () => { },
+    }
+  },
+  setup (props, context) {
+    const store = useStore()
+    let paper = ref("若CE=1,EB=3,求⊙O的半径;")
+    let paperdata = ref({
+      totalnum: 0,
+      difficulty: 0,
+      title: '',
+      paperList: []
+    })
+    let value1 = ref(4)
+    let shows = ref(false)
+    let unfoldnum = ref(-1)
+    console.log(store.state.paperData, '试卷信息')
+    function unfold (index) {
+      if (index == unfoldnum.value) {
+        console.log('进入相同判断')
+        shows.value = !shows.value
+        unfoldnum.value = -1
+      } else {
+        shows.value = !shows.value
+        console.log(shows.value, '现在的值')
+        unfoldnum.value = 1
+      }
+    }
+    function backDefault () {
+      context.emit('renew', 'default')
+    }
+    function paperInit (val) {
+      paperdata.value.totalnum = val.total
+      paperdata.value.title = val.title
+      paperdata.value.paperList = val.list
+      paperdata.value.difficulty = Number(val.difficulty)
+      console.log(paperdata.value)
+    }
+    watch(props, (newpaper) => {
+      console.log(newpaper, '监听试卷的相关内容')
+      newpaper.paperInfo ? paperInit(newpaper.paperInfo) : ''
+    }, { deep: true, })
+    return {
+      paper,
+      value1,
+      shows,
+      unfold,
+      unfoldnum,
+      backDefault,
+      paperdata
+    }
+  },
+})
+</script>
+<style scoped>
+.paperbox {
+  width: 98%;
+  min-height: 65vh;
+  background: #fff;
+  margin: 1%;
+  line-height: 20px;
+  flex-wrap: wrap;
+}
+.paperbox-header {
+  width: 100%;
+}
+.header-info {
+  display: flex;
+  border-bottom: 1px dashed #ccc;
+  height: 80px;
+  line-height: 80px;
+}
+.header-info-items {
+  display: flex;
+  width: 45%;
+}
+.header-info-title {
+  width: 18%;
+  display: flex;
+  padding-left: 15px;
+}
+.difficulty {
+  width: 35%;
+}
+.header-info-operate {
+  width: 50%;
+  display: flex;
+  flex-direction: row-reverse;
+}
+.header-info-operate div {
+  margin-right: 10px;
+}
+.paper-name {
+  font-size: 30px;
+  font-weight: bold;
+  line-height: 60px;
+  margin-top: 1%;
+}
+.paper-view-title {
+  text-align: left;
+  font-size: 18px;
+  font-weight: bold;
+  padding-left: 1%;
+}
+.aggregate {
+  font-size: 16px;
+  padding-left: 5px;
+}
+.problem {
+  position: relative;
+  cursor: pointer;
+  text-align: left;
+  margin: 1%;
+  padding: 1%;
+  border: 1px solid transparent;
+}
+.problem-details {
+  width: 85%;
+  display: inline-block;
+  vertical-align: top;
+}
+.numshow {
+  width: 15%;
+  display: inline-block;
+  vertical-align: top;
+  text-align: right;
+}
+.problem-num {
+  display: inline-block;
+  vertical-align: top;
+  width: 30px;
+  font-weight: bold;
+}
+.problem-content {
+  display: inline-block;
+  vertical-align: top;
+}
+.proble-single {
+  width: 85%;
+  margin-top: 1%;
+}
+.item-single {
+  margin: 8px 0px;
+  font-size: 16px;
+}
+.item-single div {
+  display: inline-block;
+  vertical-align: top;
+}
+.item-single-tag {
+  width: 35px;
+  font-weight: bold;
+}
+.tagicons {
+  width: 18px;
+  height: 18px;
+  fill: currentColor;
+  overflow: hidden;
+}
+.numshow-nums,
+.numshow-icon {
+  display: inline-block;
+  vertical-align: top;
+}
+.numshow-icon {
+  margin-left: 2%;
+}
+.numshow-icon-item {
+  width: 24px;
+  height: 24px;
+  background-color: #fff;
+  border: 1px solid #ccc;
+  border-radius: 50%;
+  text-align: center;
+}
+.problem:hover {
+  border: 1px solid #48dbfb;
+}
+.spreadbox {
+  margin-top: 1%;
+  padding-top: 1%;
+  /* border-top: 1px dashed #ccc; */
+  transition: all 0.8s;
+  max-height: 0;
+  overflow: hidden;
+}
+.spreadbox-title {
+  color: #48dbfb;
+}
+.unfoldIndex {
+  max-height: 230px;
+  border-top: 1px dashed #ccc;
+}
+</style>
+<style>
+.header-info .el-rate {
+  line-height: 4.7;
+}
+</style>

+ 5 - 5
TEAMModelBI/ClientApp/src/view/schoolServe/school.vue

@@ -114,7 +114,7 @@
         <el-table-column prop="location" label="位置" align="center" />
         <!-- <el-table-column prop="city" :label="$t(`schoolManages.tables.city`)" align="center" />
                 <el-table-column prop="dist" :label="$t(`schoolManages.tables.area`)" align="center" /> -->
-        <el-table-column prop="size" :label="$t(`schoolManages.tables.spacesize`)" align="center" />
+        <el-table-column prop="size" :label="$t(`schoolManages.tables.spacesize`)" sortable align="center" />
         <el-table-column :label="$t(`schoolManages.tables.assis`)" align="center">
           <template #default="scope">
             <div v-if="scope.row.assisName">{{ scope.row.assisName }}</div>
@@ -330,14 +330,14 @@ import Impower from './impower.vue'
 import Classpower from './classpower.vue'
 import setSchooladmin from './setSchooladmin.vue'
 const siteValue = window.location.host === 'localhost:5001' ? 'cn' : window.location.host === 'bi.teammodel.cn' ? 'cn' : window.location.host === 'bitest.teammodel.cn' ? 'cn' : 'international'
-//const optionsData = siteValue === 'cn' ? option_cn : option_gl
-const optionsData = siteValue === 'cn' ? option_gl : option_gl
+const optionsData = siteValue === 'cn' ? option_cn : option_gl
+//const optionsData = siteValue === 'cn' ? option_gl : option_gl
 export default {
   components: {
     SetSchool,
     Impower,
     Classpower,
-    setSchooladmin
+    setSchooladmin,
   },
   setup () {
     let { proxy } = getCurrentInstance()
@@ -1139,7 +1139,7 @@ export default {
       placeData,
       schoolregionParams,
       originalNum,
-      nSchool
+      nSchool,
     }
   },
 }

+ 2 - 2
TEAMModelBI/ClientApp/src/view/teachermanage/school.vue

@@ -46,7 +46,7 @@
       </a>
     </div>
     <div class="school-list">
-      <el-table :data="tableData" style="width: 100%" height="75vh" v-loading="loading" element-loading-text="加载中...">
+      <el-table :data="tableData" style="width: 100%" height="75vh" v-loading="loading" element-loading-text="加载中..." :default-sort="{ prop: 'scale', order: 'descending' }">
         <el-table-column prop="index" :label="$t(`schoolManages.tables.serialnum`)" type="index" sortable align="center" />
         <el-table-column :label="$t(`schoolManages.tables.badge`)" width="150" align="center">
           <template #default="scope">
@@ -59,7 +59,7 @@
                         <span>{{scope.row.period[0].name}}</span>
                     </template>
                 </el-table-column> -->
-        <el-table-column :label="$t(`schoolManages.tables.scale`)" class="school-table-edition" align="center">
+        <el-table-column prop="scale" :label="$t(`schoolManages.tables.scale`)" class="school-table-edition" align="center">
           <template #default="scope">
             <el-image style="width: 80px; height: 80px" :src="imgData.basics" fit="fill" v-if="scope.row.scale === 0"></el-image>
             <el-image style="width: 80px; height: 80px" :src="imgData.standard" fit="fill" v-else-if="scope.row.scale === 500 && scope.row.hard === 0 && scope.row.serial === 0 && scope.row.service === 0">

+ 10 - 2
TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs

@@ -1784,11 +1784,19 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                                     int grade;
                                                     if (dis > 0)
                                                     {
-                                                        grade = (Year - year - 1) % Count.Value;
+                                                        if (Year - year > 0)
+                                                        {
+                                                            grade = (Year - year - 1) % Count.Value;
+                                                        }
+                                                        else
+                                                        {
+                                                            grade = Math.Abs((Year - year)) % Count.Value;
+                                                        }
+
                                                     }
                                                     else
                                                     {
-                                                        grade = (Year - year) % Count.Value;
+                                                        grade = Math.Abs((Year - year)) % Count.Value;
                                                     }
                                                     grades.Add($"{grade}");
                                                 }

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

@@ -127,6 +127,7 @@ namespace TEAMModelOS.SDK.Models
         //补充毕业
         //0在校,1毕业 
         public int graduate { get; set; } = 0;
+        public int year { get; set; }= 0;
     }
 
     /// <summary>
@@ -209,6 +210,7 @@ namespace TEAMModelOS.SDK.Models
         public int graduate { get; set; } = 0;
         //所在名单集合
         public List<string> groupListIds { get; set; } = new List<string>();
+        public int year { get; set; }
 
     }
     public class GroupListGrp

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

@@ -57,11 +57,11 @@ namespace TEAMModelOS.SDK.Models
         /// <summary>
         ///选填  t灯,科技应用 0红灯,1 黄灯,2绿灯
         /// </summary>
-        public int tLevel { get; set; }
+        public int tLevel { get; set; } = -1;
         /// <summary>
         ///选填   p灯,教法应用 0红灯,1 黄灯,2绿灯
         /// </summary>
-        public int pLevel { get; set; }
+        public int pLevel { get; set; } = -1;
         /// <summary>
         ///选填  选用IES5的课程id 
         /// </summary>

+ 77 - 31
TEAMModelOS.SDK/Models/Service/GroupListService.cs

@@ -16,6 +16,7 @@ using TEAMModelOS.SDK.Models.Service;
 using System.Text.RegularExpressions;
 using TEAMModelOS.SDK.Models;
 using System.Net.Http;
+using DocumentFormat.OpenXml.Wordprocessing;
 
 namespace TEAMModelOS.SDK
 {
@@ -188,7 +189,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, string _stuListNo, string userid, int type, string school)
+        public static async Task<(int status, GroupList stuList,Member member)> CodeJoinList(CosmosClient client, string _stuListNo, string userid, int type, string school,int year)
         {
             var queryNo = $"SELECT  value(c)  FROM c where  c.no ='{_stuListNo}'";
             (int status, GroupList stuList,Member member) data = (-1, null,null);
@@ -197,7 +198,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);
+                    data = JoinList(item, userid, type, school,year);
                     break;
                 }
             }
@@ -209,12 +210,12 @@ namespace TEAMModelOS.SDK
                     //状态=4 表示未开放加入。
                     return (4, item, null) ;
                 }
-                data = JoinList(item, userid, type, school);
+                data = JoinList(item, userid, type, school,year);
                 break;
             }
             return data;
         }
-        public static (int status, GroupList stuList, Member member) JoinList(GroupList stuList, string userid, int type, string school)
+        public static (int status, GroupList stuList, Member member) JoinList(GroupList stuList, string userid, int type, string school,int year)
         {
             int status = -1;
             if (!string.IsNullOrWhiteSpace(stuList.school) && !string.IsNullOrWhiteSpace(school))
@@ -271,7 +272,7 @@ namespace TEAMModelOS.SDK
                     {
                         //加入成功
                         status = 0;
-                        member = new Member { id = userid, type = type, irs = irs, no = irs };
+                        member = new Member { id = userid, type = type, irs = irs, no = irs,year=year };
                         stuList.members.Add(member);
                     }
                 }
@@ -286,7 +287,7 @@ namespace TEAMModelOS.SDK
                     else
                     {
                         status = 0;
-                        member = new Member { id = userid, code = school, type = type, irs = irs, no = irs };
+                        member = new Member { id = userid, code = school, type = type, irs = irs, no = irs, year = year };
                         stuList.members.Add(member);
                     }
                 }
@@ -306,6 +307,28 @@ namespace TEAMModelOS.SDK
             string tbname = list.scope.Equals("private") ? "Teacher" : "School";
             var tmembers = list.members.Where(x => x.type == 1);
             var smembers = list.members.Where(x => x.type == 2);
+            //处理年级
+            HashSet<string> grades = new HashSet<string>();
+            if (smembers.Any() && !string.IsNullOrWhiteSpace(list.periodId) ) {
+                var hasyear = smembers.Where(z => z.year > 0 && !string.IsNullOrWhiteSpace(z.code));
+                if (hasyear.Any()) {
+                    var schoolIds = hasyear.Select(z => z.code).ToHashSet();
+                    if (schoolIds.Any()) {
+                        List<School> schools = new List<School>();
+                        string sql = $"select value c from c where c.id in ({string.Join(",", schoolIds.Select(z=>$"'{z}'"))})";
+                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.School).GetItemQueryIterator<School>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base") }))
+                        {
+                            schools.Add(item);
+                        }
+                        var codeYears = hasyear.GroupBy(z => z.code).Select(z => new { key = z.Key, years = z.Select(z => z.year).ToHashSet() });
+                        foreach (var cy in codeYears)
+                        {
+                           var school = schools.Find(z => z.id.Equals(cy.key));
+                        }
+                    }
+                    
+                }
+            }
             list.scount = smembers.Count();
             list.tcount = tmembers.Count();
             //if (smembers.Count() > 0 && smembers.Select(x => x.code).ToHashSet().Count()>=2) {
@@ -1055,7 +1078,7 @@ namespace TEAMModelOS.SDK
                         var ids = item.list.Select(x => x.id).ToList();
                         if (ids.IsNotEmpty())
                         {
-                            StringBuilder stuSql = new StringBuilder($"SELECT distinct c.name,c.id,c.code,c.picture,c.no,c.irs,c.classId ,c.graduate FROM c ");
+                            StringBuilder stuSql = new StringBuilder($"SELECT distinct c.name,c.id,c.code,c.picture,c.no,c.irs,c.classId ,c.graduate,c.year FROM c ");
                             string insql = string.Join(",", ids.Select(x => $"'{x}'"));
                             stuSql.Append($"where  c.id in ({insql})");
                             await foreach (var student in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryIterator<Student>(queryText: stuSql.ToString(),
@@ -1171,7 +1194,7 @@ namespace TEAMModelOS.SDK
 
                 if (tmdids.IsNotEmpty() && _coreAPIHttpService.check) {
                     ///获取真实的名称 ,大于50则不处理
-                    if (tmdids.Count < 50)
+                    if (tmdids.Count < 60)
                     {
                         var content = new StringContent(tmdids.Select(x => x.id).ToHashSet().ToJsonString(), Encoding.UTF8, "application/json");
                         string json = null;
@@ -1226,11 +1249,15 @@ namespace TEAMModelOS.SDK
                 students.ForEach(x =>
                 {
                     var student = studentsData.Find(y => y.id.Equals(x.id) && y.schoolId.Equals(x.code));
-                    x.name = student?.name;
-                   // x.nickname = string.IsNullOrWhiteSpace(x.nickname) ? student?.name:x.nickname;
-                    x.picture = student?.picture;
-                    x.classId = student?.classId;
-                    x.graduate = student.graduate;
+                    if (student != null)
+                    {
+                        x.name = student?.name;
+                        // x.nickname = string.IsNullOrWhiteSpace(x.nickname) ? student?.name:x.nickname;
+                        x.picture = student?.picture;
+                        x.classId = student?.classId;
+                        x.graduate = student.graduate;
+                        x.year = student.year;
+                    }
                 });
                 var mbs = tmdids;
                 mbs.AddRange(students);
@@ -1244,25 +1271,43 @@ namespace TEAMModelOS.SDK
                         await client.GetContainer(Constant.TEAMModelOS, groupTbname).ReplaceItemAsync(group, group.id, new PartitionKey(group.code));
                     }
                 }
-                groups.ForEach(x => x.members.ForEach(y => {
-                    if (y.type == 1)
-                    {
-                        var tmd = tmdids.Find(t => t.id.Equals(y.id));
-                        y.name = tmd?.name;
-                        //y.nickname = string.IsNullOrWhiteSpace(y.nickname) ? tmd?.nickname : y.nickname;
-                        y.picture = tmd?.picture;
-                    }
-                    if (y.type == 2)
+                groups.ForEach(x =>
+                {
+                    x.members.ForEach(y =>
                     {
-                        var student = students.Find(t => t.id.Equals(y.id) && t.code.Equals(y.code));
-                        y.name = student?.name;
-                      //  y.nickname =  string.IsNullOrWhiteSpace(y.nickname) ? student?.nickname : y.nickname; 
-                        y.picture = student?.picture;
-                        y.classId = student?.classId;
-                        y.graduate = student.graduate;
+                        if (y.type == 1)
+                        {
+                            var tmd = tmdids.Find(t => t.id.Equals(y.id));
+                            y.name = tmd?.name;
+                            //y.nickname = string.IsNullOrWhiteSpace(y.nickname) ? tmd?.nickname : y.nickname;
+                            y.picture = tmd?.picture;
+                        }
+                        if (y.type == 2)
+                        {
+                            var student = students.Find(t => t.id.Equals(y.id) && t.code.Equals(y.code));
+                            if (student != null)
+                            {
+                                y.name = student?.name;
+                                //  y.nickname =  string.IsNullOrWhiteSpace(y.nickname) ? student?.nickname : y.nickname; 
+                                y.picture = student?.picture;
+                                y.classId = student?.classId;
+                                y.graduate = student.graduate;
+                                y.year = student.year;
+                            }
+                        }
+                    });
+                    if (!x.type.Equals("class")) {
+                        var yearc = x.members.Where(z => z.type == 2).GroupBy(g => g.year).Select(k => new { key = k.Key, count = k.Count() }).OrderByDescending(z => z.count);
+                        if (yearc.Any())
+                        {
+                            //有一半的人是同一个班的,则以
+                            if (yearc.First().count * 1.0 / x.members.Count > 0.51)
+                            {
+                                x.year = yearc.First().key;
+                            }
+                        }
                     }
-                }));
-
+                });
                 HashSet<string> schoolCodes = groups.SelectMany(x => x.members).Where(y => !string.IsNullOrEmpty(y.code)).Select(z => z.code).ToHashSet();
                 if (schoolCodes != null && schoolCodes.Count > 0)
                 {
@@ -1278,6 +1323,7 @@ namespace TEAMModelOS.SDK
                             var school = schools.Find(j => j.id.Equals(z.code));
                             z.schoolName = school?.name;
                         });
+
                     }
                 }
                 if (graduate >= 0)
@@ -1290,12 +1336,12 @@ namespace TEAMModelOS.SDK
                         });
                     }
                     mbs.RemoveAll(z => z.graduate != graduate);
+                    return (groups, mbs);
                 }
                 //直接返回
                 else {
                     return (groups, mbs);
                 }
-              
             }
             catch (Exception ex)
             {

+ 58 - 0
TEAMModelOS.SDK/Models/Service/SchoolService.cs

@@ -20,6 +20,64 @@ namespace TEAMModelOS.SDK
 {
     public class SchoolService
     {
+        /// <summary>
+        /// 根据年份获取年级
+        /// </summary>
+        /// <param name="semesterList"></param>
+        /// <returns></returns>
+        public static List<KeyValuePair<int, string>> GetGrades(School school,string periodId ,List<int> years,long time =0) {
+            var date = DateTimeOffset.UtcNow;
+            //2001-09-09 09:46:40
+            if (time > 1000000000000) {
+                date = DateTimeOffset.FromUnixTimeMilliseconds(time);
+            }
+            //年级算法
+            var period = school.period.Find(x => x.id.Equals(periodId));
+            int? Count = period?.grades?.Count;
+            List<KeyValuePair<int, string>> yearGrades = new List<KeyValuePair<int, string>>();
+            if (Count.HasValue)
+            {
+                int Day = date.Day;
+                int Month = date.Month;
+                int Year = date.Year;
+                int start = int.Parse($"{Year}0901");
+                var se = period.semesters.Find(x => x.start == 1);
+                if (se == null)
+                {
+                    se = period.semesters.First();
+                }
+                string sm = "09";
+                string sd = "01";
+                if (se != null)
+                {
+                    sm = se.month >= 10 ? $"{se.month}" : $"0{se.month}";
+                    sd = se.day >= 10 ? $"{se.day}" : $"0{se.day}";
+                    start = int.Parse($"{Year}{sm}{sd}");
+                }
+                int curr = int.Parse(date.ToString("yyyyMMdd"));
+                //新学年开学时间大于当前时间,计算年级需要减1   20220901-20220408 > 0 则当前20220408是2021年入学的,
+                //当前时间大于新学年开学时间,计算年级则不需要  20220901-20221203 < 1 则当前20221203是2022年入学的,
+                //20230901-20230101 > 0 则当前20230101是2022年入学的,
+                int dis = start - curr;
+                foreach (int year in years)
+                {
+                    if (int.Parse($"{year}{sm}{sd}") < curr) {
+                        int grade;
+                        if (dis > 0)
+                        {
+                            grade = Math.Abs((Year - year - 1)) % Count.Value;
+                        }
+                        else
+                        {
+                            grade = Math.Abs((Year - year)) % Count.Value;
+                        }
+                        yearGrades.Add(new KeyValuePair<int, string>(year, $"{grade}"));
+                    }
+                }
+            }
+            return yearGrades;
+        }
+
         /// <summary>
         /// 处理学期排序
         /// </summary>

+ 1 - 1
TEAMModelOS.SDK/Models/Service/StudentService.cs

@@ -33,7 +33,7 @@ namespace TEAMModelOS.SDK
             List<Student> studentDatas = new List<Student>();
             if (students.Any())
             {
-                string queryText = $"SELECT c.id, c.code ,c.classId  FROM c  WHERE c.id IN ({string.Join(",", students.Select(o => $"'{o}'"))})";
+                string queryText = $"SELECT c.id, c.code ,c.classId ,c.year FROM c  WHERE c.id IN ({string.Join(",", students.Select(o => $"'{o}'"))})";
                 await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryIterator<Student>(queryText: queryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{schoolId}") }))
                 {
                     studentDatas.Add(item);

+ 0 - 6
TEAMModelOS.sln

@@ -13,8 +13,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelOS", "TEAMModelOS\
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelBI", "TEAMModelBI\TEAMModelBI.csproj", "{54DC5894-D5BA-40AB-9226-FB801E04BA24}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelAPI", "TEAMModelAPI\TEAMModelAPI.csproj", "{C8E1DCAE-BE26-49E8-A772-3A094FC510DE}"
-EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -41,10 +39,6 @@ Global
 		{54DC5894-D5BA-40AB-9226-FB801E04BA24}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{54DC5894-D5BA-40AB-9226-FB801E04BA24}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{54DC5894-D5BA-40AB-9226-FB801E04BA24}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C8E1DCAE-BE26-49E8-A772-3A094FC510DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C8E1DCAE-BE26-49E8-A772-3A094FC510DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C8E1DCAE-BE26-49E8-A772-3A094FC510DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C8E1DCAE-BE26-49E8-A772-3A094FC510DE}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

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

@@ -568,6 +568,7 @@ const LANG_EN_US = {
         authType: 'Authorization Method:',
         authType1: 'New Contracts',
         authType2: 'Renewal',
+        authType3: '变更',
         authNumber: 'Purchase No.:',
         text1: 'Device Name:',
         text2: 'Device:',
@@ -3023,6 +3024,7 @@ const LANG_EN_US = {
         edit: 'Edit Record',
         editTitle: 'Edit Lesson',
         addTitle: 'Add Lesson',
+        today: 'Today',
         week: 'Week',
         month: 'Month',
         semester: 'Semester',
@@ -5846,7 +5848,10 @@ const LANG_EN_US = {
             'research-upd': 'Manage Lesson Management',
             'link': 'Resource Platform',
             'link-read': 'View Resource Platform',
-            'link-upd': 'Manage Resource Platform'
+            'link-upd': 'Manage Resource Platform',
+            'art': 'Art evaluation',
+            'art-read':'View Art Evaluation',
+            'art-upd':'Manage Art Evaluation'
         },
         modal: {
             text1: 'The authorization of this account has been changed, do you want to give this account a more appropriate title?',

+ 9 - 4
TEAMModelOS/ClientApp/public/lang/zh-CN.js

@@ -568,6 +568,7 @@ const LANG_ZH_CN = {
         authType: '授权方式:',
         authType1: '新约',
         authType2: '续约',
+        authType3: '变更',
         authNumber: '购买数量:',
         text1: '设备名称:',
         text2: '硬件:',
@@ -3016,13 +3017,14 @@ const LANG_ZH_CN = {
         setting: '课堂记录设置',
         all: '不限',
         cate: '类别',
-        range: '范围',
+        range: '时间',
         rangeTip: '选择起止时间',
         more: '更多',
         close: '收起',
         edit: '编辑记录',
         editTitle: '编辑课例',
         addTitle: '新增课例',
+        today: '今日',
         week: '本周',
         month: '本月',
         semester: '本学期',
@@ -3048,7 +3050,7 @@ const LANG_ZH_CN = {
         lessonName: '课堂名称',
         lessonNamePlace: '请输入课例名称...',
         grade: '年级',
-        subject: '科',
+        subject: '科',
         search: '查询',
         reset: '重置',
         resultTip1: '共查询到',
@@ -3071,7 +3073,7 @@ const LANG_ZH_CN = {
         score: '总互动分',
         interactionCount: '互动题数',
         clientInteractionCount: '互动教学',
-        examQuizCount: '精准教学',
+        examQuizCount: '测验教学',
         examPointRate: '测验得分率',
         action: '操作',
         allTable: '课例数据汇总表',
@@ -5851,7 +5853,10 @@ const LANG_ZH_CN = {
             'research-upd': '课例中心管理(修改)权限',
             'link': '资源平台',
             'link-read': '查看资源平台',
-            'link-upd': '管理(修改)资源平台'
+            'link-upd': '管理(修改)资源平台',
+            'art': '艺术评测',
+            'art-read':'艺术评测查看权限',
+            'art-upd':'艺术评测管理权限'
         },
         modal: {
             text1: '此账号权限已变更,是否要给此账号更加合适的职称',

+ 23 - 18
TEAMModelOS/ClientApp/public/lang/zh-TW.js

@@ -568,6 +568,7 @@ const LANG_ZH_TW = {
         authType: '授權方式:',
         authType1: '新約',
         authType2: '續約',
+        authType3: '变更',
         authNumber: '購買數量:',
         text1: '設備名稱:',
         text2: '設備:',
@@ -3025,6 +3026,7 @@ const LANG_ZH_TW = {
         edit: '編輯記錄',
         editTitle: '編輯記錄',
         addTitle: '新增記錄',
+        today: '今日',
         week: '本週',
         month: '本月',
         semester: '本學期',
@@ -3568,23 +3570,23 @@ const LANG_ZH_TW = {
         addSubjectType2: '選擇已有學科',
         addSubjectType3: '已有學科',
         addSubjectType4: '請選擇需要新增的學科',
-        pdtyp1:'學前',
-        pdtyp2:'小學',
-        pdtyp3:'國中',
-        pdtyp4:'高中',
-        pdtyp5:'高職',
-        pdtyp6:'專科',
-        pdtyp7:'大學',
-        pdtyp8:'特殊教育',
-        pdtyp9:'教育局',
-        pdtyp10:'資教部門',
-        pdtyp11:'社區專科',
-        pdtyp12:'社區大學',
-        pdtyp13:'碩士研究生',
-        pdtyp14:'博士研究生',
-        pdtyp15:'企業',
-        pdtyp16:'設置學段類型',
-        pdtyp17:'學段類型',
+        pdtyp1: '學前',
+        pdtyp2: '小學',
+        pdtyp3: '國中',
+        pdtyp4: '高中',
+        pdtyp5: '高職',
+        pdtyp6: '專科',
+        pdtyp7: '大學',
+        pdtyp8: '特殊教育',
+        pdtyp9: '教育局',
+        pdtyp10: '資教部門',
+        pdtyp11: '社區專科',
+        pdtyp12: '社區大學',
+        pdtyp13: '碩士研究生',
+        pdtyp14: '博士研究生',
+        pdtyp15: '企業',
+        pdtyp16: '設置學段類型',
+        pdtyp17: '學段類型',
 
         // ClassroomSetting.vue
         classroomList: '教室清單',
@@ -5851,7 +5853,10 @@ const LANG_ZH_TW = {
             'research-upd': '課堂紀錄管理(修改)權限',
             'link': '資源平臺',
             'link-read': '查看資源平臺',
-            'link-upd': '管理(修改)資源平臺'
+            'link-upd': '管理(修改)資源平臺',
+            'art': '藝術評測',
+            'art-read':'藝術評測查看權限',
+            'art-upd':'藝術評測管理權限'
         },
         modal: {
             text1: '此帳號權限已變更,是否要給此帳號更加合適的職稱',

+ 25 - 22
TEAMModelOS/ClientApp/src/api/lessonRecord.js

@@ -1,51 +1,54 @@
 import { post } from '@/api/http'
 export default {
-	/* 获取课例统计数量 */
+    /* 获取课例统计数量 */
     getLessonCount: function (data) {
         return post('/common/lesson-record/get-lesson-record-count', data)
     },
     // 查询课堂记录列表
-	getLessonList: function (data) {
+    getLessonList: function (data) {
         return post('/common/lesson-record/get-lesson-record', data)
     },
     // 查询课堂记录列表(不分个人还是校本课程)
-	getLessonListAll: function (data) {
+    getLessonListAll: function (data) {
         return post('/common/lesson-record/get-lesson-record-schorpvt', data)
     },
-	getDashboardData: function (data) {
+    getStaticData: function (data) {
+        return post('/class/analysis/analysis-record-count', data)
+    },
+    getDashboardData: function (data) {
         return post('/class/analysis/analysis-recod', data)
     },
-	getAnalysisCount: function (data) {
+    getAnalysisCount: function (data) {
         return post('/class/analysis/settle-recod', data)
     },
     getTeacherRecordData: function (data) {
         return post('/class/analysis/analysis-recod-teacher', data)
     },
-	// 课堂记录tag维护接口
-	optSetting: function (data) {
+    // 课堂记录tag维护接口
+    optSetting: function (data) {
         return post('/school/setting/opt-setting', data)
     },
     //删除课堂记录
     delRcd: function (data) {
         return post('/common/lesson-record/delete-lesson-record', data)
-    }, 
-	// 查询学校设置的课例类别
-	findLessonSettings: function (data) {
+    },
+    // 查询学校设置的课例类别
+    findLessonSettings: function (data) {
         return post('/school/setting/find-id', data)
-    }, 
-	// 设置学校的课例类别
-	setLessonTags: function (data) {
+    },
+    // 设置学校的课例类别
+    setLessonTags: function (data) {
         return post('/school/setting/opt-setting', data)
-    }, 
-	/* 更新课例 */
-	updateLesson: function (data) {
+    },
+    /* 更新课例 */
+    updateLesson: function (data) {
         return post('/common/lesson-record/update-lesson-baseinfo', data)
-    }, 
-	/* 获取推荐课例 */
-	getIntroLessons: function (data) {
-	    return post('/common/lesson-record/get-other-lesson-record', data)
-	}, 
-	// 根据id 查询课堂记录
+    },
+    /* 获取推荐课例 */
+    getIntroLessons: function (data) {
+        return post('/common/lesson-record/get-other-lesson-record', data)
+    },
+    // 根据id 查询课堂记录
     getLessonInfo: function (data) {
         return post("/common/lesson-record/get-lesson-record-id", data)
     },

+ 21 - 7
TEAMModelOS/ClientApp/src/common/BaseLayout.vue

@@ -263,6 +263,9 @@ export default {
     IES5Menu() {
       return !this.$jsFn.checkJinNiu() && !this.$jsFn.checkTrain()
     },
+    hasDashAuth() {
+      return window.location.host.includes('test.teammodel') || ['habook', 'ydzt', 'cdydzt', 'hbcn'].includes(this.$store.state.userInfo.schoolCode)
+    },
     jinniuMenu() {
       return this.$jsFn.checkJinNiu()
     },
@@ -274,14 +277,25 @@ export default {
         //数据看板
         {
           icon: 'iconfont icon-data-count',
-          name: this.$t('system.menu.researchBoard'),
-          router: '/home/Dashboard',
+          name: '学生看板',
+          router: '/fiveEdu',
           tag: '',
           role: 'admin',
           permission: 'dashboard-read',
-          menuName: 'Dashboard',
+          menuName: 'StuDashboard',
           child: [],
-          isShow: this.IES5Menu
+          isShow: this.IES5Menu && this.hasDashAuth
+        },
+        {
+          icon: 'iconfont icon-data-count',
+          name: '教学看板',
+          router: '/researchDashboard',
+          tag: '',
+          role: 'admin',
+          permission: 'dashboard-read',
+          menuName: 'TeacherDashboard',
+          child: [],
+          isShow: this.IES5Menu && this.hasDashAuth
         },
         // 学校管理
         {
@@ -604,7 +618,7 @@ export default {
           router: '',
           tag: '',
           role: 'admin',
-          permission: '',
+          permission: 'art-read|art-upd',
           subName: 'artExam',
           menuName: 'artExam',
           child: [
@@ -614,7 +628,7 @@ export default {
               router: '/home/mgtArtExam',
               tag: '',
               role: 'admin',
-              permission: '',
+              permission: 'art-read|art-upd',
               menuName: 'mgtArtExam',
               isShow: this.IES5Menu && this.$store.state.config.srvAdr == 'China'
             },
@@ -624,7 +638,7 @@ export default {
               router: '/home/ArtAssessment',
               tag: '',
               role: 'admin',
-              permission: '',
+              permission: 'art-read|art-upd',
               menuName: 'ArtAssessment',
               isShow: this.IES5Menu && this.$store.state.config.srvAdr == 'China'
             },

+ 1 - 1
TEAMModelOS/ClientApp/src/components/research-dashboard/BaseTechBar.vue

@@ -13,7 +13,7 @@ export default {
       let myChart = this.$echarts.init(document.getElementById('baseTechBar'))
       var echartsData = {
         title: 'title',
-        city: ['互动教学', '合作学习', '差异教学', '精准教学'],
+        city: ['互动教学', '合作学习', '差异教学', '测验教学'],
         legend: data.legend,
         data: data.data,
         total: data.total,

+ 14 - 24
TEAMModelOS/ClientApp/src/components/research-dashboard/LeftTop.vue

@@ -6,8 +6,8 @@
 		</p> -->
     <div class="up">
       <div class="bg-color-black item" v-for="item in titleItem" :key="item.title">
-        <p class="ml-3 colorBlue fw-b fs-xl">{{ item.title }}</p>
         <countTo :startVal='0' :endVal='item.number' :duration='2000' class="count-num"></countTo>
+        <p class="ml-3 colorBlue fw-b fs-xl">{{ item.title }}</p>
       </div>
     </div>
   </div>
@@ -45,25 +45,17 @@ export default {
           number: 0
         },
         {
-          title: vm.$t('lessonRecord.echarts.count6'),
+          title: `年级数`,
+          number: 0
+        },
+        {
+          title: `学科数`,
           number: 0
         },
-        // {
-        // 	title: vm.$t('lessonRecord.echarts.count7'),
-        // 	number: 0
-        // },
-        // {
-        // 	title: vm.$t('lessonRecord.echarts.count8'),
-        // 	number: 0
-        // },
-        // {
-        // 	title: vm.$t('lessonRecord.echarts.count9'),
-        // 	number: 0
-        // },
-        // {
-        // 	title: vm.$t('lessonRecord.echarts.count10'),
-        // 	number: 0
-        // }
+        {
+          title: `教研组数`,
+          number: 0
+        }
       ],
     }
   },
@@ -77,11 +69,9 @@ export default {
       totalJson.forEach(i => {
         this.titleItem.find(j => j.key === i.name).number = i.value
       })
-      this.titleItem[5].number = allJson.teachCount
-      // this.titleItem[6].number = allJson.taskCount
-      // this.titleItem[7].number = allJson.workCount
-      // this.titleItem[8].number = allJson.examQuizCount
-      // this.titleItem[9].number = allJson.interactCount
+      this.titleItem[5].number = allJson.classify_grade.length
+      this.titleItem[6].number = allJson.classify_sub.length
+      this.titleItem[7].number = allJson.classify_group.length
     }
   }
 }
@@ -102,7 +92,7 @@ export default {
     flex-wrap: wrap;
 
     .item {
-      width: 14.8%;
+      width: 23.2%;
       border-radius: 6px;
       padding: 8px;
       margin: 0.3% 0.9% 1.3% 0.9%;

+ 5 - 5
TEAMModelOS/ClientApp/src/router/routes.js

@@ -1091,7 +1091,7 @@ export const routes = [{
         path: '/researchDashboard',
         component: () => import('@/view/dashboard/Research.vue'),
         meta: {
-            activeName: 'Dashboard',
+            activeName: 'TeacherDashboard',
             middleware: ['login', 'ability:admin,dashboard-read'],
         }
     },
@@ -1128,7 +1128,7 @@ export const routes = [{
         // component: () => import('@/view/dashboard/StudentAll.vue'),
         component: () => import('@/view/dashboard/fiveEdu/FiveEdu.vue'),
         meta: {
-            activeName: 'Dashboard',
+            activeName: 'StuDashboard',
             middleware: ['login', 'ability:admin,dashboard-read'],
         }
     },
@@ -1326,7 +1326,7 @@ export const routes = [{
         component: () => import('@/view/artexam/Mgt.vue'),
         meta: {
             activeName: 'artExam',
-            middleware: ['login', 'ability:admin'],
+            middleware: ['login', 'ability:admin,art-read|art-upd'],
         }
     },
     //创建艺术评测
@@ -1336,7 +1336,7 @@ export const routes = [{
         component: () => import('@/view/artexam/Create.vue'),
         meta: {
             activeName: 'artExam',
-            middleware: ['login', 'ability:admin'],
+            middleware: ['login', 'ability:admin,art-upd'],
         }
     },
     //艺术评测打分
@@ -1346,7 +1346,7 @@ export const routes = [{
         component: () => import('@/view/assessment/ArtAssessment.vue'),
         meta: {
             activeName: 'artExam',
-            middleware: ['login', 'ability:admin'],
+            middleware: ['login', 'ability:admin,art-upd'],
         }
     }
     ]

+ 2 - 2
TEAMModelOS/ClientApp/src/view/artexam/Mgt.vue

@@ -4,10 +4,10 @@
             <div class="art-exam-list-wrap" slot="left">
                 <div class="art-mgt-top light-iview-select light-iview-input">
                     <span>{{$t('ae.ae28')}}</span>
-                    <span class="to-create-art" @click="toCreate">
+                    <span class="to-create-art" @click="toCreate" v-if="$access.can('admin.*|art-upd')">
                         <Icon type="md-add" />
                     </span>
-                    <span class="to-create-art" @click="delArt" v-show="artInfo.owner === 'school'">
+                    <span class="to-create-art" @click="delArt" v-show="artInfo.owner === 'school'" v-if="$access.can('admin.*|art-upd')">
                         <Icon type="md-trash" />
                     </span>
                 </div>

+ 286 - 286
TEAMModelOS/ClientApp/src/view/auth/ProdRecord.vue

@@ -1,325 +1,325 @@
 <template>
-    <div class="prod-record-container">
-        <vuescroll>
-            <div class="prod-record-box">
-                <h1 class="record-title">
-                    {{$t('auth.recordTitle')}}
-                </h1>
-                <p class="back-page" @click="backPage">
-                    <Icon type="md-arrow-round-back" style="margin-right:5px" />
-                    {{$t('auth.backPage')}}
-                </p>
-                <Timeline style="margin-top:30px">
-                    <TimelineItem v-for="order in orderList" :key="order.id">
-                        <p class="order-time">
-                            {{$jsFn.dateFormat(order.date)}}
-                        </p>
-                        <div class="content">
-                            <!-- 序列号 -->
-                            <p v-if="order.serial && order.serial.length" class="order-type-title">
-                                {{$t('auth.text4')}}</p>
-                            <template v-if="order.serial && order.serial.length">
-                                <div v-for="(serial) in order.serial" :key="serial.prodCode" class="serial-wrap-item">
-                                    <div class="serial-info-item">
-                                        <p class="serial-attr-label">
-                                            {{$t('auth.serialLabel')}}
-                                        </p>
-                                        <ul style="margin-left:15px;font-weight: 900;color: black;">
-                                            <li v-for="sCode in serial.sn" :key="sCode">
-                                                {{sCode}}
-                                            </li>
-                                        </ul>
-                                    </div>
-                                    <div class="serial-info-item">
-                                        <p class="serial-attr-label">
-                                            {{$t('auth.authDate')}}
-                                        </p>
-                                        <p>
-                                            <span v-if="serial.sdate">
-                                                {{$jsFn.dateFormat(serial.sdate)}}-
-                                            </span>
-                                            {{$jsFn.dateFormat(serial.edate)}}
-                                        </p>
-                                    </div>
-                                    <div class="serial-info-item">
-                                        <p class="serial-attr-label">
-                                            {{$t('auth.fuAuth')}}</p>
-                                        <div>
-                                            <template v-for="(aitem) in serialAuthList">
-                                                <Tag :key="aitem.code" class="serial-auth-tag" v-show="serial.authKey.includes(aitem.code)" :color="aitem.color">
-                                                    <span class="serial-auth-name">
-                                                        {{aitem.name}}
-                                                    </span>
-                                                    <span v-show="aitem.type == 'number'" class="serial-auth-number">
-                                                        {{aitem.type == 'number' && serial.aprule ? serial.aprule[aitem.code] : ''}}
-                                                    </span>
-                                                </Tag>
-                                            </template>
-                                        </div>
-                                    </div>
-                                    <div class="serial-info-item">
-                                        <p class="serial-attr-label">
-                                            {{$t('auth.IRSnumber')}}</p>
-                                        <p>
-                                            {{serial.cqty}}
-                                        </p>
-                                    </div>
-                                    <div class="serial-info-item">
-                                        <p class="serial-attr-label">
-                                            {{$t('auth.bandDeviceNO')}}</p>
-                                        <p>
-                                            {{serial.device}}
-                                        </p>
-                                    </div>
-                                </div>
-                            </template>
-                            <!-- 服务类授权 -->
-                            <p v-if="order.service && order.service.length" class="order-type-title">
-                                {{$t('auth.text3')}}</p>
-                            <template v-if="order.service && order.service.length">
-                                <div v-for="service in order.service" :key="service.prodCode + service.sdate" class="serial-wrap-item">
-                                    <div class="service-info-item">
-                                        <p class="serial-attr-label">
-                                            {{$t('auth.svcName')}}
-                                        </p>
-                                        <p style="font-weight: 900;color: black;">
-                                            {{getProductName(service.prodCode)}}
-                                        </p>
-                                    </div>
-                                    <div class="service-info-item">
-                                        <p class="serial-attr-label">
-                                            {{$t('auth.authType')}}
-                                        </p>
-                                        <p>
-                                            {{service.type == 'N' ? $t('auth.authType1') : $t('auth.authType2')}}
-                                        </p>
-                                    </div>
-                                    <div class="service-info-item">
-                                        <p class="serial-attr-label">
-                                            {{$t('auth.authDate')}}
-                                        </p>
-                                        <p>
-                                            {{$jsFn.dateFormat(service.sdate)}}
-                                            -
-                                            {{$jsFn.dateFormat(service.edate)}}
-                                        </p>
-                                    </div>
-                                    <div class="service-info-item" v-show="service.number">
-                                        <p class="serial-attr-label">
-                                            {{$t('auth.authNumber')}}
-                                        </p>
-                                        <p>
-                                            {{ service.number }}
-                                            <span v-if="service.unit">
-                                                ({{service.unit}})
-                                            </span>
-                                        </p>
-                                    </div>
-                                </div>
-                            </template>
-                            <!-- 硬件类 -->
-                            <p v-if="order.hard && order.hard.length" class="order-type-title">
-                                {{$t('auth.text2')}}
-                            </p>
-                            <template v-if="order.hard && order.hard.length">
-                                <div v-for="(hard,index) in order.hard" :key="hard.prodCode + index" class="serial-wrap-item">
-                                    <div class="service-info-item">
-                                        <p class="serial-attr-label">
-                                            {{$t('auth.text1')}}
-                                        </p>
-                                        <p>
-                                            {{getProductName(hard.prodCode)}}
-                                        </p>
-                                    </div>
-                                </div>
-                            </template>
-                        </div>
-                    </TimelineItem>
-                </Timeline>
-                <EmptyData v-show="!orderList.length" :textContent="$t('auth.noRecord')" :top="200"></EmptyData>
+  <div class="prod-record-container">
+    <vuescroll>
+      <div class="prod-record-box">
+        <h1 class="record-title">
+          {{$t('auth.recordTitle')}}
+        </h1>
+        <p class="back-page" @click="backPage">
+          <Icon type="md-arrow-round-back" style="margin-right:5px" />
+          {{$t('auth.backPage')}}
+        </p>
+        <Timeline style="margin-top:30px">
+          <TimelineItem v-for="order in orderList" :key="order.id">
+            <p class="order-time">
+              {{$jsFn.dateFormat(order.date)}}
+            </p>
+            <div class="content">
+              <!-- 序列号 -->
+              <p v-if="order.serial && order.serial.length" class="order-type-title">
+                {{$t('auth.text4')}}</p>
+              <template v-if="order.serial && order.serial.length">
+                <div v-for="(serial) in order.serial" :key="serial.prodCode" class="serial-wrap-item">
+                  <div class="serial-info-item">
+                    <p class="serial-attr-label">
+                      {{$t('auth.serialLabel')}}
+                    </p>
+                    <ul style="margin-left:15px;font-weight: 900;color: black;">
+                      <li v-for="sCode in serial.sn" :key="sCode">
+                        {{sCode}}
+                      </li>
+                    </ul>
+                  </div>
+                  <div class="serial-info-item">
+                    <p class="serial-attr-label">
+                      {{$t('auth.authDate')}}
+                    </p>
+                    <p>
+                      <span v-if="serial.sdate">
+                        {{$jsFn.dateFormat(serial.sdate)}}-
+                      </span>
+                      {{$jsFn.dateFormat(serial.edate)}}
+                    </p>
+                  </div>
+                  <div class="serial-info-item">
+                    <p class="serial-attr-label">
+                      {{$t('auth.fuAuth')}}</p>
+                    <div>
+                      <template v-for="(aitem) in serialAuthList">
+                        <Tag :key="aitem.code" class="serial-auth-tag" v-show="serial.authKey.includes(aitem.code)" :color="aitem.color">
+                          <span class="serial-auth-name">
+                            {{aitem.name}}
+                          </span>
+                          <span v-show="aitem.type == 'number'" class="serial-auth-number">
+                            {{aitem.type == 'number' && serial.aprule ? serial.aprule[aitem.code] : ''}}
+                          </span>
+                        </Tag>
+                      </template>
+                    </div>
+                  </div>
+                  <div class="serial-info-item">
+                    <p class="serial-attr-label">
+                      {{$t('auth.IRSnumber')}}</p>
+                    <p>
+                      {{serial.cqty}}
+                    </p>
+                  </div>
+                  <div class="serial-info-item">
+                    <p class="serial-attr-label">
+                      {{$t('auth.bandDeviceNO')}}</p>
+                    <p>
+                      {{serial.device}}
+                    </p>
+                  </div>
+                </div>
+              </template>
+              <!-- 服务类授权 -->
+              <p v-if="order.service && order.service.length" class="order-type-title">
+                {{$t('auth.text3')}}</p>
+              <template v-if="order.service && order.service.length">
+                <div v-for="service in order.service" :key="service.prodCode + service.sdate" class="serial-wrap-item">
+                  <div class="service-info-item">
+                    <p class="serial-attr-label">
+                      {{$t('auth.svcName')}}
+                    </p>
+                    <p style="font-weight: 900;color: black;">
+                      {{getProductName(service.prodCode)}}
+                    </p>
+                  </div>
+                  <div class="service-info-item">
+                    <p class="serial-attr-label">
+                      {{$t('auth.authType')}}
+                    </p>
+                    <p>
+                      {{service.type == 'N' ? $t('auth.authType1') : service.type == 'G' ? '变更' : service.type == 'C' ? $t('auth.authType2') : ''}}
+                    </p>
+                  </div>
+                  <div class="service-info-item">
+                    <p class="serial-attr-label">
+                      {{$t('auth.authDate')}}
+                    </p>
+                    <p>
+                      {{$jsFn.dateFormat(service.sdate)}}
+                      -
+                      {{$jsFn.dateFormat(service.edate)}}
+                    </p>
+                  </div>
+                  <div class="service-info-item" v-show="service.number">
+                    <p class="serial-attr-label">
+                      {{$t('auth.authNumber')}}
+                    </p>
+                    <p>
+                      {{ service.number }}
+                      <span v-if="service.unit">
+                        ({{service.unit}})
+                      </span>
+                    </p>
+                  </div>
+                </div>
+              </template>
+              <!-- 硬件类 -->
+              <p v-if="order.hard && order.hard.length" class="order-type-title">
+                {{$t('auth.text2')}}
+              </p>
+              <template v-if="order.hard && order.hard.length">
+                <div v-for="(hard,index) in order.hard" :key="hard.prodCode + index" class="serial-wrap-item">
+                  <div class="service-info-item">
+                    <p class="serial-attr-label">
+                      {{$t('auth.text1')}}
+                    </p>
+                    <p>
+                      {{getProductName(hard.prodCode)}}
+                    </p>
+                  </div>
+                </div>
+              </template>
             </div>
-        </vuescroll>
-    </div>
+          </TimelineItem>
+        </Timeline>
+        <EmptyData v-show="!orderList.length" :textContent="$t('auth.noRecord')" :top="200"></EmptyData>
+      </div>
+    </vuescroll>
+  </div>
 </template>
 <script>
 export default {
-    props: {
-        order: {
-            type: Array,
-            default: () => {
-                return []
-            }
-        }
-    },
-    data() {
-        return {
-            serialAuthList: [
-                {
-                    code: 'sokapp',
-                    name: this.$t('auth.attr1'),
-                    type: 'tag',
-                    color: 'geekblue'
-                },
-                {
-                    code: 'sokvdo',
-                    name: this.$t('auth.attr2'),
-                    type: 'tag',
-                    color: 'orange'
-                },
-                {
-                    code: 'sokrpt',
-                    name: this.$t('auth.attr3'),
-                    type: 'tag',
-                    color: 'yellow'
-                },
-                {
-                    code: 'sokdesk',
-                    name: this.$t('auth.attr4'),
-                    type: 'tag',
-                    color: 'green'
-                },
-                {
-                    code: 'ezs',
-                    name: this.$t('auth.attr5'),
-                    type: 'tag',
-                    color: 'cyan'
-                },
-                {
-                    code: 'remotcls',
-                    name: this.$t('auth.attr6'),
-                    type: 'tag',
-                    color: 'blue'
-                },
-                {
-                    code: 'irs',
-                    name: this.$t('auth.attr7'),
-                    type: 'tag',
-                    color: 'purple'
-                },
-                {
-                    code: 'hdcam',
-                    name: this.$t('auth.attr8'),
-                    type: 'tag',
-                    color: 'red'
-                },
-                {
-                    code: 'wordanls',
-                    name: this.$t('auth.attr9'),
-                    type: 'tag',
-                    color: 'volcano'
-                },
-                {
-                    code: 'soknumber',
-                    name: this.$t('auth.attr10'),
-                    type: 'number',
-                    color: 'magenta'
-                },
-                {
-                    code: 'cligroup',
-                    name: this.$t('auth.attr11'),
-                    type: 'number',
-                    color: 'red'
-                }
-            ],
-            orderList: [],
-            productList: []
-        }
-    },
-
-    methods: {
-        backPage() {
-            this.$emit('on-back')
+  props: {
+    order: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data() {
+    return {
+      serialAuthList: [
+        {
+          code: 'sokapp',
+          name: this.$t('auth.attr1'),
+          type: 'tag',
+          color: 'geekblue'
+        },
+        {
+          code: 'sokvdo',
+          name: this.$t('auth.attr2'),
+          type: 'tag',
+          color: 'orange'
+        },
+        {
+          code: 'sokrpt',
+          name: this.$t('auth.attr3'),
+          type: 'tag',
+          color: 'yellow'
+        },
+        {
+          code: 'sokdesk',
+          name: this.$t('auth.attr4'),
+          type: 'tag',
+          color: 'green'
         },
-        formatList() {
-            this.orderList = this.order
-            this.orderList.forEach(order => {
-                order.serial?.forEach(s => {
-                    s.authKey = Object.keys(s.aprule || {})
-                })
-            })
-            this.orderList.sort((a, b) => {
-                return b.date - a.date
-            })
+        {
+          code: 'ezs',
+          name: this.$t('auth.attr5'),
+          type: 'tag',
+          color: 'cyan'
         },
-        getProductName(code) {
-            let p = this.productList.find(item => item.code == code)
-            return p && p.name ? p.name : ''
+        {
+          code: 'remotcls',
+          name: this.$t('auth.attr6'),
+          type: 'tag',
+          color: 'blue'
         },
+        {
+          code: 'irs',
+          name: this.$t('auth.attr7'),
+          type: 'tag',
+          color: 'purple'
+        },
+        {
+          code: 'hdcam',
+          name: this.$t('auth.attr8'),
+          type: 'tag',
+          color: 'red'
+        },
+        {
+          code: 'wordanls',
+          name: this.$t('auth.attr9'),
+          type: 'tag',
+          color: 'volcano'
+        },
+        {
+          code: 'soknumber',
+          name: this.$t('auth.attr10'),
+          type: 'number',
+          color: 'magenta'
+        },
+        {
+          code: 'cligroup',
+          name: this.$t('auth.attr11'),
+          type: 'number',
+          color: 'red'
+        }
+      ],
+      orderList: [],
+      productList: []
+    }
+  },
+
+  methods: {
+    backPage() {
+      this.$emit('on-back')
     },
-    created() {
-        this.productList = this.$GLOBAL.PROD_CODE()
+    formatList() {
+      this.orderList = this.order
+      this.orderList.forEach(order => {
+        order.serial?.forEach(s => {
+          s.authKey = Object.keys(s.aprule || {})
+        })
+      })
+      this.orderList.sort((a, b) => {
+        return b.date - a.date
+      })
     },
-    watch: {
-        order: {
-            deep: true,
-            immediate: true,
-            handler(n, o) {
-                if (n) this.formatList()
-            }
-        }
+    getProductName(code) {
+      let p = this.productList.find(item => item.code == code)
+      return p && p.name ? p.name : ''
+    },
+  },
+  created() {
+    this.productList = this.$GLOBAL.PROD_CODE()
+  },
+  watch: {
+    order: {
+      deep: true,
+      immediate: true,
+      handler(n, o) {
+        if (n) this.formatList()
+      }
     }
+  }
 }
 </script>
 <style scoped lang="less">
 .service-info-item {
-    margin-top: 10px;
-    display: flex;
+  margin-top: 10px;
+  display: flex;
 }
 .service-wrap-item {
-    margin-top: 15px;
-    padding: 10px;
+  margin-top: 15px;
+  padding: 10px;
 }
 .serial-wrap-item {
-    padding: 10px;
+  padding: 10px;
 }
 .serial-wrap-item:hover {
-    background: #f0f0f0;
+  background: #f0f0f0;
 }
 .order-time {
-    color: #17233d;
-    font-size: 16px;
-    font-weight: 800;
+  color: #17233d;
+  font-size: 16px;
+  font-weight: 800;
 }
 .serial-info-item {
-    margin-top: 10px;
-    display: flex;
+  margin-top: 10px;
+  display: flex;
 }
 .serial-attr-label {
-    color: #808695;
-    min-width: 120px;
+  color: #808695;
+  min-width: 120px;
 }
 .prod-record-container {
-    width: 100%;
-    height: 100%;
-    padding: 20px;
-    background: #f3f3f3;
+  width: 100%;
+  height: 100%;
+  padding: 20px;
+  background: #f3f3f3;
 }
 .prod-record-box {
-    border-radius: 5px;
-    background: white;
-    width: 1200px;
-    min-height: 700px;
-    margin: auto;
-    padding: 20px 30px;
-    box-shadow: -2px 0px 5px #e9e9e9;
+  border-radius: 5px;
+  background: white;
+  width: 1200px;
+  min-height: 700px;
+  margin: auto;
+  padding: 20px 30px;
+  box-shadow: -2px 0px 5px #e9e9e9;
 }
 .back-page {
-    color: #2db7f5;
-    cursor: pointer;
-    user-select: none;
-    margin-top: -30px;
-    font-size: 16px;
-    float: right;
+  color: #2db7f5;
+  cursor: pointer;
+  user-select: none;
+  margin-top: -30px;
+  font-size: 16px;
+  float: right;
 }
 .record-title {
-    text-align: center;
-    font-size: 20px;
+  text-align: center;
+  font-size: 20px;
 }
 .order-type-title {
-    font-size: 14px;
-    font-weight: 800;
-    color: #17233d;
-    margin-top: 20px;
-    padding-left: 10px;
+  font-size: 14px;
+  font-weight: 800;
+  color: #17233d;
+  margin-top: 20px;
+  padding-left: 10px;
 }
 </style>

+ 2 - 2
TEAMModelOS/ClientApp/src/view/dashboard/Research.less

@@ -192,12 +192,12 @@
 
         &-top {
           width: 100%;
-          height: 12%;
+          height: 22%;
         }
 
         &-bottom {
           width: 100%;
-          height: 83%;
+          height: 73%;
         }
       }
 

+ 1 - 1
TEAMModelOS/ClientApp/src/view/dashboard/Research.vue

@@ -124,7 +124,7 @@ export default {
     },
     goBack() {
       this.$tools.exitFullscreen()
-      this.$router.push('/home/Dashboard')
+      this.$router.push('/home/homePage')
     },
     timeFn() {
       this.timing = setInterval(() => {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/dashboard/Student.vue

@@ -245,7 +245,7 @@ export default {
   methods: {
     goQuit() {
       this.$tools.exitFullscreen()
-      this.$router.push('/home/Dashboard')
+      this.$router.push('/home/homePage')
     },
     goBack() {
       this.$parent.isAll = true

+ 1 - 1
TEAMModelOS/ClientApp/src/view/dashboard/StudentAll.vue

@@ -346,7 +346,7 @@ export default {
     },
     goBack() {
       this.$tools.exitFullscreen()
-      this.$router.push('/home/Dashboard')
+      this.$router.push('/home/homePage')
     },
     timeFn() {
       this.timing = setInterval(() => {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/dashboard/fiveEdu/FiveEdu.less

@@ -154,7 +154,7 @@
             width: 100%;
             display: flex;
             padding: 10px;
-            font-size: 18px;
+            font-size: 16px;
             font-weight: bold;
             align-items: center;
 

+ 1 - 1
TEAMModelOS/ClientApp/src/view/dashboard/fiveEdu/FiveEdu.vue

@@ -401,7 +401,7 @@ export default {
     },
     goBack() {
       this.$tools.exitFullscreen()
-      this.$router.push('/home/Dashboard')
+      this.$router.push('/home/homePage')
     },
     timeFn() {
       this.timing = setInterval(() => {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/dashboard/style.less

@@ -18,7 +18,7 @@
   padding: 0px 5px 0 5px;
   border-radius: 10px 10px 0 0;
   height: 50px;
-  font-size: 18px;
+  font-size: 16px;
   font-weight: 700;
 
   .ivu-icon {

+ 56 - 4
TEAMModelOS/ClientApp/src/view/research-center/ResearchMgt.less

@@ -3,13 +3,45 @@
 	// padding: 5px 25px;
 	background-color: #f6f7f7;
 
+	.static-box {
+		display: flex;
+		background-color: #ffffff;
+		align-items: center;
+		padding: 20px 25px;
+
+		.split-line {
+			width: 2px;
+			height: 30px;
+			margin: 0 20px;
+			background-color: rgb(238, 238, 238)
+		}
+
+		.static-item {
+			position: relative;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+			padding: 0 20px;
+
+			&:first-child {
+				padding-left: 10px;
+			}
 
 
+			.static-value {
+				font-size: 26px;
+				font-weight: bold;
+				color: #00b4eb;
+			}
+		}
+	}
+
 	.filter-box {
+		position: relative;
 		padding: 5px 25px 10px 25px;
 		background-color: #ffffff;
 		border-bottom: 1px dashed #ccc;
-		position: relative;
 
 		.search-result {
 			position: absolute;
@@ -68,6 +100,7 @@
 
 		.advanced-wrap {
 			padding: 0 15px;
+
 			.clean-item {
 				margin: 15px 0;
 				display: flex;
@@ -81,14 +114,14 @@
 			}
 		}
 
-		
+
 
 		.ad-filter {
 			display: flex;
 			padding: 10px 0;
 
 			.ad-filter-item {
-				margin-right: 20px;
+				margin-right: 10px;
 
 				.filter-item-title {
 					margin-right: 10px;
@@ -111,7 +144,7 @@
 				}
 
 				/deep/ .ivu-icon-ios-close {
-					color:rgb(85, 85, 85) !important;
+					color: rgb(85, 85, 85) !important;
 				}
 			}
 		}
@@ -136,6 +169,25 @@
 	.table-box {
 		overflow: auto;
 
+		/deep/ .ivu-table-header thead tr th {
+			padding: 12px 0;
+			border-top: 1px solid rgb(235, 231, 231);
+		}
+
+		/deep/ .ivu-scroll-container {
+			.ivu-scroll-loader:first-child {
+				display: none;
+			}
+		}
+
+		.level-light {
+			display: inline-block;
+			width: 25px;
+			height: 25px;
+			border-radius: 50px;
+			margin: 10px 0;
+		}
+
 		.action-icon {
 			margin-right: 10px;
 			font-size: 18px;

+ 129 - 108
TEAMModelOS/ClientApp/src/view/research-center/ResearchMgt.vue

@@ -1,7 +1,43 @@
 <template>
   <div class="research-mgmt-container">
+    <div class="static-box">
+      <div class="static-item">
+        <span class="static-value">{{ analysisCount[0].value }}</span>
+        <span class="static-label">总课例数</span>
+      </div>
+      <div class="split-line"></div>
+      <div class="static-item">
+        <span class="static-value">{{ analysisCount[1].value }}</span>
+        <span class="static-label">今日课例</span>
+      </div>
+      <div class="split-line"></div>
+      <div class="static-item">
+        <span class="static-value">{{ analysisCount[2].value }}</span>
+        <span class="static-label">本周课例</span>
+      </div>
+      <div class="split-line"></div>
+      <div class="static-item">
+        <span class="static-value">{{ analysisCount[3].value }}</span>
+        <span class="static-label">本月课例</span>
+      </div>
+      <div class="split-line"></div>
+      <div class="static-item">
+        <span class="static-value">{{ analysisCount[4].value }}</span>
+        <span class="static-label">本学期课例</span>
+      </div>
+      <div class="split-line"></div>
+      <div class="static-item">
+        <span class="static-value">{{ curPeriod.subjects.length }}</span>
+        <span class="static-label">学科数</span>
+      </div>
+      <div class="split-line"></div>
+      <div class="static-item">
+        <span class="static-value">{{ curPeriod.grades.length }}</span>
+        <span class="static-label">年级数</span>
+      </div>
+    </div>
     <!-- 筛选区域 -->
-    <div class="filter-box">
+    <div class="filter-box" v-show="isShowFilter">
       <div class="filter-section">
         <span class="filter-title">{{ $t('lessonRecord.subject') }}</span>
         <div class="filter-items">
@@ -17,16 +53,15 @@
         </div>
       </div>
       <div class="filter-section">
-        <span class="filter-title">{{ $t('lessonRecord.cate') }}</span>
+        <span class="filter-title">{{ $t('lessonRecord.range') }}</span>
         <div class="filter-items">
-          <span :class="['filter-item',!tagIndexArr.length ? 'filter-item-active' : '']" @click="onFilterChange('tag',-1)">{{ $t('lessonRecord.all') }}</span>
-          <span :class="['filter-item',tagIndexArr.includes(index) ? 'filter-item-active' : '']" v-for="(item,index) in tagList" :key="index" @click="onFilterChange('tag',index)">{{ item }}</span>
+          <span :class="['filter-item',curRangeIndex === index ? 'filter-item-active' : '']" v-for="(item,index) in rangeArr" :key="index" @click="onFilterChange('range',index)">{{ item }}</span>
         </div>
       </div>
       <div class="filter-section">
-        <span class="filter-title">{{ $t('lessonRecord.range') }}</span>
+        <span class="filter-title">类型</span>
         <div class="filter-items">
-          <span :class="['filter-item',curRangeIndex === index ? 'filter-item-active' : '']" v-for="(item,index) in rangeArr" :key="index" @click="onFilterChange('range',index)">{{ item }}</span>
+          <span :class="['filter-item',curTypeIndex === index ? 'filter-item-active' : '']" v-for="(item,index) in typeArr" :key="index" @click="onFilterChange('type',index)">{{ item }}</span>
         </div>
       </div>
       <div class="filter-section">
@@ -36,15 +71,26 @@
         </div>
       </div>
       <div class="ad-filter">
-        <div class="ad-filter-item" v-show="!hideAdFilter && !showRangePicker">
-          <!-- <span class="filter-item-title">{{ $t('lessonRecord.tchName') }}</span> -->
+        <div class="ad-filter-item">
+          <Select v-model="tagIndexArr" style="width:150px;" placeholder="课例类别" multiple @on-change="onCateChange">
+            <Option v-for="(item,index) in tagList" :value="index">{{ item }}</Option>
+          </Select>
+        </div>
+        <div class="ad-filter-item">
+          <Select v-model="filterClassIds" style="width:150px;" placeholder="选择班级">
+            <Option v-for="(item,index) in classArr" :value="item.id">{{ item.name }}</Option>
+          </Select>
+        </div>
+        <div class="ad-filter-item">
           <BaseSelectTch @onTchSelect="onTchSelect" ref="tchSelect"></BaseSelectTch>
         </div>
-        <div class="ad-filter-item" v-show="!hideAdFilter && !showRangePicker">
-          <!-- <span class="filter-item-title">{{ $t('lessonRecord.lessonName') }}</span> -->
+        <div class="ad-filter-item">
           <Input v-model="filterJson.vName" :placeholder="$t('lessonRecord.lessonNamePlace')" clearable />
         </div>
-        <div class="ad-filter-item" v-show="!hideAdFilter && !showRangePicker">
+        <div class="ad-filter-item">
+          <DatePicker :value="filterJson.timeRange" :editable="false" :options="timeOptions" format="yyyy/MM/dd" type="daterange" placement="bottom-end" :placeholder="$t('lessonRecord.rangeTip')" @on-change="onTimeRangeChange"></DatePicker>
+        </div>
+        <div class="ad-filter-item">
           <div class="cond-items" style="display: inline-block;vertical-align: sub;margin-right:10px;">
             <span v-for="(cond,condIndex) in conds">
               <Tag v-if="cond.val > 0" color="purple" size="medium" closable @on-close="removeAdvanceFilter(condIndex)">{{ cond.name }}{{ cond.type }}{{ cond.val }}</Tag>
@@ -68,10 +114,7 @@
             </div>
           </Dropdown>
         </div>
-        <div class="ad-filter-item" v-show="showRangePicker">
-          <DatePicker :value="filterJson.timeRange" :editable="false" :options="timeOptions" format="yyyy/MM/dd" type="daterange" placement="bottom-end" :placeholder="$t('lessonRecord.rangeTip')" @on-change="onTimeRangeChange"></DatePicker>
-        </div>
-        <div class="ad-filter-item" v-show="!hideAdFilter || showRangePicker">
+        <div class="ad-filter-item">
           <Button type="primary" shape="circle" @click="doSearch">{{ $t('lessonRecord.search') }}</Button>
           <Button type="info" shape="circle" @click="doReset">{{ $t('lessonRecord.reset') }}</Button>
         </div>
@@ -79,9 +122,9 @@
       </div>
       <!-- 查询结果 -->
       <div class="search-result">
-        <span style="cursor: pointer;margin-right: 10px;color: #04abc8;" @click="onClickAdFilter">
+        <!-- <span style="cursor: pointer;margin-right: 10px;color: #04abc8;" @click="onClickAdFilter">
           <Icon type="ios-funnel" color="#04abc8" style="margin-right: 5px;" />{{ hideAdFilter ? $t('lessonRecord.more') : $t('lessonRecord.close') }}
-        </span>
+        </span> -->
         <span style="cursor: pointer;margin-right: 10px;color: #04abc8;" @click="exportTable">
           <Icon type="md-download" color="#04abc8" style="margin:5px;" />{{ $t('assessment.export') }}
         </span>
@@ -89,17 +132,12 @@
           </span>{{ $t('lessonRecord.resultTip2') }}</span>
       </div>
     </div>
-
     <!-- 工具栏 -->
     <div class="tools-bar">
-      <!-- <div class="tool-item" @click="onAddVideo">
-				<Icon type="md-add" />
-				<span>添加课例</span>
-			</div> -->
-      <!-- <div class="tool-item">
-				<Icon type="md-download" @click="exportTable()"/>
-				<span>{{ $t('lessonRecord.export') }}</span>
-			</div> -->
+      <div class="tool-item" @click="isShowFilter = !isShowFilter">
+        <Icon type="md-funnel" />
+        <span>{{ isShowFilter ? '收起筛选' : '展开筛选'}}</span>
+      </div>
       <div class="tool-item" @click="onTagMgClick">
         <Icon type="logo-buffer" />
         <span>{{ $t('lessonRecord.tagMg') }}</span>
@@ -108,10 +146,6 @@
         <Icon type="md-settings" />
         <span>{{ $t('lessonRecord.setting') }}</span>
       </div>
-      <!-- <div class="tool-item">
-				<Icon type="ios-paper-plane" />
-				<span>分享至公开课</span>
-			</div> -->
     </div>
     <!-- 表格区域 -->
     <div class="table-box">
@@ -138,21 +172,14 @@
               </div>
             </div>
           </template>
-          <!-- <template slot-scope="{ row }" slot="category">
-            <span>{{ row.category.length ? row.category.join(',') : '-' }}</span>
+          <!-- 科技手段分数 -->
+          <template slot-scope="{ row,index }" slot="tLevel">
+            <span :style="{ backgroundColor: getLevelColor(row.tLevel),boxShadow:'0 0 6px ' + getLevelColor(row.tLevel) }" class="level-light"></span>
           </template>
-          <template slot-scope="{ row }" slot="subject">
-            <span>{{ curPeriod.subjects.find(j => j.id === row.subjectId).name  }}</span>
+          <!-- 教法应用分数 -->
+          <template slot-scope="{ row,index }" slot="pLevel">
+            <span :style="{ backgroundColor: getLevelColor(row.pLevel),boxShadow:'0 0 6px rgba(0, 0, 0, 0.5)' }" class="level-light"></span>
           </template>
-          <template slot-scope="{ row }" slot="grade">
-            <span>{{ row.grade.map(i => curPeriod.grades[+i]).join(',') }}</span>
-          </template>
-          <template slot-scope="{ row }" slot="className">
-            <span>{{ row.groupIds.join(',') }}</span>
-          </template>
-          <template slot-scope="{ row }" slot="startTime">
-            <span>{{ $tools.formatTime(row.startTime,'yyyy-MM-dd') }}</span>
-          </template> -->
           <template slot-scope="{ row }" slot="action">
             <div v-if="row.status !== 404">
               <Icon type="md-download" class="action-icon" color="#34cf97" @click="downloadTable(row)" :title="$t('lessonRecord.action1')" />
@@ -227,10 +254,15 @@ export default {
   },
   data(vm) {
     return {
-      rangeArr: [vm.$t('lessonRecord.all'), vm.$t('lessonRecord.week'), vm.$t('lessonRecord.month'), vm.$t('lessonRecord.semester'), vm.$t('lessonRecord.custom')],
+      filterClassIds: [],
+      classArr: [],
+      rangeArr: [vm.$t('lessonRecord.all'), vm.$t('lessonRecord.today'), vm.$t('lessonRecord.week'), vm.$t('lessonRecord.month'), vm.$t('lessonRecord.semester'), vm.$t('lessonRecord.custom')],
       statusArr: [vm.$t('lessonRecord.normalStatus'), vm.$t('lessonRecord.expireStatus'), vm.$t('lessonRecord.deleteStatus')],
+      typeArr: [vm.$t('lessonRecord.all'), '双绿灯课例', '双红灯课例'],
       curRangeIndex: 0,
       curStatusIndex: 0,
+      curTypeIndex: 0,
+      isShowFilter: false,
       hideAdFilter: true,
       cleanModal: false,
       showRangePicker: false,
@@ -241,7 +273,7 @@ export default {
       apiTags: [],
       oldNewTags: [],
       analysisArr: [vm.$t('lessonRecord.count1'), vm.$t('lessonRecord.count2'), vm.$t('lessonRecord.count3'), vm.$t('lessonRecord.count4'), vm.$t('lessonRecord.count5'), vm.$t('lessonRecord.count6'), vm.$t('lessonRecord.count7')],
-      analysisCount: [],
+      analysisCount: [0, 0, 0, 0, 0, 0],
       isEdit: false,
       editLoading: false,
       tagLoading: false,
@@ -416,77 +448,39 @@ export default {
           key: 'clientInteractionCount',
           sortable: true,
           ellipsis: true,
+          align: 'center'
         },
         {
           title: vm.$t('lessonRecord.collateTaskCount'),
           key: 'collateTaskCount',
           sortable: true,
           ellipsis: true,
+          align: 'center'
         },
         {
           title: vm.$t('lessonRecord.pushCount'),
           key: 'pushCount',
           sortable: true,
           ellipsis: true,
+          align: 'center'
         },
         {
           title: vm.$t('lessonRecord.examQuizCount'),
           key: 'examCount',
           sortable: true,
           ellipsis: true,
+          align: 'center'
+        },
+        {
+          title: `科技互动(T分)`,
+          slot: 'tLevel',
+          align: 'center'
+        },
+        {
+          title: `教法应用(P分)`,
+          slot: 'pLevel',
+          align: 'center'
         },
-        // {
-        //   title: vm.$t('lessonRecord.attendCount'),
-        //   key: 'attendRate',
-        //   sortable: true,
-        //   ellipsis: true,
-        //   render: function (h, params) {
-        //     return h('span', (Number(params.row.attendRate)).toFixed(2) + '%')
-        //   },
-        // },
-        // {
-        //   title: vm.$t('lessonRecord.groupCount'),
-        //   key: 'groupCount',
-        //   sortable: true,
-        //   ellipsis: true,
-        // },
-        // {
-        //   title: vm.$t('lessonRecord.totalPoint'),
-        //   key: 'totalPoint',
-        //   sortable: true,
-        //   ellipsis: true,
-        // },
-
-        // {
-        //   title: vm.$t('lessonRecord.collateCount'),
-        //   key: 'collateCount',
-        //   sortable: true,
-        //   ellipsis: true,
-        // },
-
-        // {
-        //   title: vm.$t('lessonRecord.score'),
-        //   key: 'totalInteractPoint',
-        //   sortable: true,
-        //   ellipsis: true,
-        // },
-        // {
-        //   title: vm.$t('lessonRecord.interactionCount'),
-        //   key: 'interactionCount',
-        //   sortable: true,
-        //   ellipsis: true,
-        // },
-
-
-        // {
-        //   title: vm.$t('lessonRecord.examPointRate'),
-        //   key: 'examPointRate',
-        //   sortable: true,
-        //   ellipsis: true,
-        //   render: function (h, params) {
-        //     return h('span', (Number(params.row.examPointRate)).toFixed(2) + '%')
-        //   },
-        // },
         {
           title: vm.$t('lessonRecord.action'),
           slot: 'action',
@@ -632,14 +626,14 @@ export default {
     /* 获取课例统计数据 */
     getAnalysisCount() {
       let semesterRange = this.$tools.getSemesterTimeRange()
-      this.$api.lessonRecord.getAnalysisCount({
+      this.$api.lessonRecord.getStaticData({
         "stime": semesterRange.st,
         "etime": semesterRange.et,
         "code": this.$store.state.userInfo.schoolCode,
         "periodId": this.$store.state.user.curPeriod.id
       }).then(res => {
         console.log(res)
-        this.analysisCount = Object.values(res)
+        this.analysisCount = res.total
       })
     },
     /* 保存课例保留时间设置 */
@@ -728,6 +722,11 @@ export default {
         subjectId: '',
         timeRange: []
       }
+      this.curStatusIndex = 0
+      this.curTypeIndex = 0
+      this.curRangeIndex = 0
+      this.subjectIndexArr = []
+      this.gradeIndexArr = []
       this.conds.forEach(i => {
         i.val = 0
         i.type = '>='
@@ -754,6 +753,9 @@ export default {
       }
       this.doFilter()
     },
+    onCateChange(val) {
+      this.onFilterChange('tag', val)
+    },
     /* 筛选操作 */
     onFilterChange(type, index) {
       if (type === 'grade') {
@@ -775,36 +777,38 @@ export default {
         }
         this.filterParams.subjectId = index === -1 ? [] : this.subjectIndexArr.map(j => this.curPeriod.subjects[j].id)
       } else if (type === 'tag') {
-        if (index === -1) {
+        if (index.length == 0) {
           this.tagIndexArr = []
-        } else if (this.tagIndexArr.includes(index)) {
-          this.tagIndexArr.splice(this.tagIndexArr.indexOf(index), 1)
-        } else {
-          this.tagIndexArr.push(index)
         }
         this.filterParams.category = this.tagIndexArr.map(i => this.tagList[i])
       } else if (type === 'range') {
         this.curRangeIndex = index
         if (index === 1) {
+          const nowTime = new Date();
+          const todayStart = new Date(nowTime.toDateString()).getTime();
+          const todayEnd = new Date(nowTime.toDateString()).getTime() + 3600 * 1000 * 24 - 1;
+          this.filterParams.stime = todayStart
+          this.filterParams.etime = todayEnd
+        } else if (index === 2) {
           const end = new Date();
           const nowWeekDay = end.getDay() //本周的第几天
           const start = new Date();
           this.filterParams.stime = new Date(start.toLocaleDateString()).getTime() - 3600 * 1000 * 24 * (nowWeekDay - 1)
           this.filterParams.etime = end.getTime()
-        } else if (index === 2) {
+        } else if (index === 3) {
           const end = new Date();
           let curYear = end.getFullYear()
           let curMonth = end.getMonth() + 1
           const start = new Date(`${curYear}/${curMonth}/01`);
           this.filterParams.stime = start.getTime()
           this.filterParams.etime = end.getTime()
-        } else if (index === 3) {
+        } else if (index === 4) {
           let semesterRange = this.$tools.getSemesterTimeRange()
           this.filterJson.sTime = semesterRange.st
           this.filterJson.eTime = semesterRange.et
           this.filterParams.stime = semesterRange.st
           this.filterParams.etime = semesterRange.et
-        } else if (index === 4) {
+        } else if (index === 5) {
           this.showRangePicker = true
           return
         } else {
@@ -831,6 +835,18 @@ export default {
           this.filterParams.expire = false
           this.filterParams.isOk = true
         }
+      } else if (type === 'type') {
+        this.curTypeIndex = index
+        if (index === 0) {
+          this.filterParams.doubleGreen = false
+          this.filterParams.doubleRed = false
+        } else if (index === 1) {
+          this.filterParams.doubleGreen = true
+          this.filterParams.doubleRed = false
+        } else if (index === 2) {
+          this.filterParams.doubleGreen = false
+          this.filterParams.doubleRed = true
+        }
       }
       this.doFilter()
     },
@@ -1050,6 +1066,11 @@ export default {
     curPeriod() {
       return this.$store.state.user.curPeriod
     },
+    getLevelColor() {
+      return level => {
+        return ['#ff2d2d', '#ffc018', '#00b214'][level]
+      }
+    }
   },
   watch: {
     '$store.state.user.curPeriod': {
@@ -1059,7 +1080,7 @@ export default {
         if (n) {
           this.initFilter()
           this.initTags()
-          // this.getAnalysisCount()
+          this.getAnalysisCount()
         }
       }
     }

+ 2 - 1
TEAMModelOS/ClientApp/src/view/student-account/stulist/MgtStuList.vue

@@ -542,7 +542,8 @@ export default {
                         irs: irs + '',
                         name: item.name,
                         className: item.className,
-                        picture: item.picture
+                        picture: item.picture,
+                        year: item.year
                     })
                     this.stuListShow[this.curIndex].scount++
                 }

+ 5 - 3
TEAMModelOS/ClientApp/src/view/teachermgmt/components/mgt/TeacherMgt.vue

@@ -1220,12 +1220,13 @@ export default {
                 res => {
                     // 暂时去掉四类(课纲、内容、题库、知识点)校本资源的读取权限,老师加入学校默认会添加这四个权限
                     let auth = ['content-read', 'exercise-read', 'knowledge-read', 'syllabus-read']
+                    let globalDeL = ['train','art']
                     for (let i = 0; i < res.authoritylist.length; i++) {
                         if (auth.includes(res.authoritylist[i].rowKey)) {
                             res.authoritylist.splice(i, 1)
                             --i
                         }
-                        if (this.$store.state.config.srvAdr == 'Global' && res.authoritylist[i].category === 'train') {
+                        if (this.$store.state.config.srvAdr == 'Global' && globalDeL.includes(res.authoritylist[i].category)) {
                             res.authoritylist.splice(i, 1)
                             --i
                         }
@@ -1245,8 +1246,9 @@ export default {
                         schoolAc: 11,
                         research: 12,
                         train: 13,
-                        analysis: 14,
-                        link: 15,
+                        art: 14,
+                        analysis: 15,
+                        link: 16,
                     }
                     res.authoritylist.sort((a, b) => {
                         return sortMap[a.category] - sortMap[b.category]

+ 5 - 2
TEAMModelOS/Controllers/Both/GroupListController.cs

@@ -130,7 +130,8 @@ namespace TEAMModelOS.Controllers
                     await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").CreateItemAsync<TmdUser>(tmduser, new PartitionKey("Base"));
                 }
             }
-            (int status, GroupList stuList,Member member) data = await GroupListService.CodeJoinList(client, $"{_stuListNo}", id, type: 1, $"{school}");
+            int year = DateTimeOffset.UtcNow.Year;
+            (int status, GroupList stuList,Member member) data = await GroupListService.CodeJoinList(client, $"{_stuListNo}", id, type: 1, $"{school}",year);
             //没有TmdUser时
             if (data.status == 0)
             {
@@ -215,11 +216,13 @@ namespace TEAMModelOS.Controllers
             string no = null;
             var client = _azureCosmos.GetCosmosClient();
             HttpContext?.Items.TryGetValue("Scope", out scope);
+            int year = DateTimeOffset.UtcNow.Year;
             if ($"{scope}".Equals(Constant.ScopeStudent))
             {
                 type = 2;
                 Student student = await client.GetContainer(Constant.TEAMModelOS, "Student").ReadItemAsync<Student>(userid, new PartitionKey($"Base-{school}"));
                 no = student.no;
+                year = student.year;
 
             }
             if ($"{scope}".Equals(Constant.ScopeTmdUser))
@@ -230,7 +233,7 @@ namespace TEAMModelOS.Controllers
             {
                 type = 1;
             }
-            (int status, GroupList stuList, Member member) data = await GroupListService.CodeJoinList(client, $"{_stuListNo}", userid, type, school);
+            (int status, GroupList stuList, Member member) data = await GroupListService.CodeJoinList(client, $"{_stuListNo}", userid, type, school,year);
             if (data.status == 0)
             {
 

+ 5 - 2
TEAMModelOS/Controllers/OpenApi/OpenSchool/ScGroupListController.cs

@@ -335,6 +335,7 @@ namespace TEAMModelOS.Controllers
                     {
                         if (infos.Any())
                         {
+                            int year = DateTimeOffset.UtcNow.Year;
                             infos.ToList().ForEach(x =>
                             {
                                 var mebJoined = list.members.Find(m => m.id.Equals(x.id) && m.type == 1);
@@ -360,10 +361,11 @@ namespace TEAMModelOS.Controllers
                                     mebJoined.nickname = mb.nickname == null ? mebJoined.nickname : mb.nickname;
                                     mebJoined.groupName = groupName == null ? mebJoined.groupName : groupName;
                                     mebJoined.groupId = groupId == null ? mebJoined.groupId : groupId;
+                                    mebJoined.year = year;
                                 }
                                 else
                                 {
-                                    (int status, GroupList stuList, Member member) = GroupListService.JoinList(list, x.id, 1, school);
+                                    (int status, GroupList stuList, Member member) = GroupListService.JoinList(list, x.id, 1, school,year);
                                     member.nickname = mb.nickname == null ? mebJoined.nickname : mb.nickname;
                                     member.groupName = groupName == null ? member.groupName : groupName;
                                     member.groupId = groupId == null ? member.groupId : groupId;
@@ -396,10 +398,11 @@ namespace TEAMModelOS.Controllers
                                     mebJoined.nickname = mb.nickname == null ? mebJoined.nickname : mb.nickname;
                                     mebJoined.groupName = groupName == null ? mebJoined.groupName : groupName;
                                     mebJoined.groupId = groupId == null ? mebJoined.groupId : groupId;
+                                    mebJoined.year = x.year;
                                 }
                                 else
                                 {
-                                    (int status, GroupList stuList, Member member) = GroupListService.JoinList(list, x.id, 2, school);
+                                    (int status, GroupList stuList, Member member) = GroupListService.JoinList(list, x.id, 2, school,x.year);
                                     member.nickname = mb.nickname == null ? mebJoined.nickname : mb.nickname;
                                     member.groupName = groupName == null ? member.groupName : groupName;
                                     member.groupId = groupId == null ? member.groupId : groupId;

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

@@ -397,7 +397,7 @@ namespace TEAMModelOS.Controllers
                                     await client.GetContainer(Constant.TEAMModelOS, Constant.Student).ReplaceItemAsync(rs, rs.id, new PartitionKey(rs.code));
                                 }
                                 if (artResults.Any()) {
-                                    List<ArtStudentPdf> studentPdfs = await ArtService.GenArtPDF(artResults, $"{_artId}", $"{school}", head_lang, _azureCosmos, _environment, _coreAPIHttpService, _dingDing, _serviceBus, _configuration);
+                                    List<ArtStudentPdf> studentPdfs = await ArtService.GenArtPDF(artResults.Select(z=>z.studentId).ToList(), $"{_artId}", $"{school}", head_lang, _azureCosmos, _environment, _coreAPIHttpService, _dingDing, _serviceBus, _configuration);
                                 }
                                 return Ok(new { results = studentArtResults, status = 1 });
                             }

+ 21 - 0
TEAMModelOS/Controllers/XTest/FixLessonRecordController.cs

@@ -38,6 +38,7 @@ using DocumentFormat.OpenXml.Drawing.Diagrams;
 using TEAMModelOS.SDK.Models.Dtos;
 using DocumentFormat.OpenXml.Bibliography;
 using System.Formats.Asn1;
+using Microsoft.Azure.SignalR.Protocol;
 
 namespace TEAMModelOS.Controllers.XTest
 {
@@ -68,6 +69,26 @@ namespace TEAMModelOS.Controllers.XTest
             _coreAPIHttpService = coreAPIHttpService;
             _httpClient = httpClient;
         }
+
+
+
+        /// <summary>
+        ///
+        /// </summary>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("test-lesson-grade")]
+        public async Task<IActionResult> TestLessonGrade(JsonElement json)
+        {
+            string school = json.GetProperty("school").GetString();
+            string periodId = json.GetProperty("periodId").GetString();
+            List<int> years = json.GetProperty("years").Deserialize<List<int >>();
+            long time  = json.GetProperty("time").Deserialize<long  >();
+            var client = _azureCosmos.GetCosmosClient();
+            School schoolObj = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(school, new PartitionKey("Base"));
+            var grades= SchoolService.GetGrades(schoolObj, $"{periodId}", years, time);
+            return Ok(grades);
+        }
         /// <summary>
         ///
         /// </summary>

+ 4 - 4
TEAMModelOS/TEAMModelOS.csproj

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