zhouj1203@hotmail.com 2 vuotta sitten
vanhempi
commit
4e4f5376ad
32 muutettua tiedostoa jossa 1235 lisäystä ja 230 poistoa
  1. 1 1
      TEAMModelBI/ClientApp/public/index.html
  2. 255 0
      TEAMModelBI/ClientApp/src/view/participation/examination.vue
  3. 149 87
      TEAMModelBI/ClientApp/src/view/participation/index.vue
  4. 23 16
      TEAMModelBI/ClientApp/src/view/participation/setPhase.vue
  5. 7 10
      TEAMModelBI/ClientApp/src/view/schoolServe/setschool.vue
  6. 19 11
      TEAMModelBI/Controllers/BINormal/BatchAreaController.cs
  7. 3 3
      TEAMModelBI/Controllers/BISchool/SchoolController.cs
  8. 52 20
      TEAMModelBI/Controllers/BITest/TestController.cs
  9. 3 3
      TEAMModelBI/TEAMModelBI.csproj
  10. 1 1
      TEAMModelOS.SDK/Models/Cosmos/BI/AreaQuoteRecord.cs
  11. 4 1
      TEAMModelOS.SDK/Models/Cosmos/Normal/Area.cs
  12. 30 0
      TEAMModelOS.SDK/Models/Service/BatchCopyFileService.cs
  13. 61 6
      TEAMModelOS.SDK/Models/Service/Common/ActivityStudentService.cs
  14. 1 0
      TEAMModelOS/ClientApp/package.json
  15. 1 1
      TEAMModelOS/ClientApp/public/lang/zh-CN.js
  16. 1 1
      TEAMModelOS/ClientApp/public/lang/zh-TW.js
  17. 4 0
      TEAMModelOS/ClientApp/src/api/areaArt.js
  18. 4 4
      TEAMModelOS/ClientApp/src/common/BaseLayout.vue
  19. 33 8
      TEAMModelOS/ClientApp/src/view/areaArtExam/DataView.vue
  20. 59 33
      TEAMModelOS/ClientApp/src/view/areaArtExam/Mgt.vue
  21. 1 1
      TEAMModelOS/ClientApp/src/view/areaMgmt/AreaLayout.vue
  22. 2 1
      TEAMModelOS/ClientApp/src/view/artexam/Mgt.vue
  23. 2 0
      TEAMModelOS/ClientApp/src/view/artexam/QuoTree.vue
  24. 10 3
      TEAMModelOS/ClientApp/src/view/assessment/ArtAssessment.vue
  25. 2 1
      TEAMModelOS/ClientApp/src/view/jyzx/offline.vue
  26. 2 0
      TEAMModelOS/ClientApp/src/view/student-account/stulist/MgtStuList.vue
  27. 2 1
      TEAMModelOS/ClientApp/src/view/teachcontent/index.vue
  28. 16 11
      TEAMModelOS/ClientApp/vue.config.js
  29. 3 3
      TEAMModelOS/Controllers/Common/AreaController.cs
  30. 2 2
      TEAMModelOS/Controllers/OpenApi/OpenApiService.cs
  31. 481 0
      TEAMModelOS/Controllers/XTest/FixDataController.cs
  32. 1 1
      TEAMModelOS/TEAMModelOS.csproj

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

+ 255 - 0
TEAMModelBI/ClientApp/src/view/participation/examination.vue

@@ -0,0 +1,255 @@
+<template>
+  <div class="examinationbox">
+    <div class="header-filter">
+      <el-collapse v-model="activeNames" accordion>
+        <el-collapse-item title="进阶筛选" name="1">
+          <div>
+            Consistent with real life: in line with the process and logic of real
+            life, and comply with languages and habits that the users are used to;
+          </div>
+          <div>
+            Consistent within interface: all elements should be consistent, such
+            as: design style, icons and texts, position of elements, etc.
+          </div>
+        </el-collapse-item>
+      </el-collapse>
+    </div>
+    <div class="middlebox">
+      <div class="middlebox-content">
+        <div class="middlebox-left">
+          <div class="middlebox-left-tag">
+            <span>标签:</span>
+            <el-select v-model="findbox.tagValue" class="m-2" placeholder="请选择" size="small">
+              <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+          </div>
+          <div class="middlebox-left-serach">
+            <el-input v-model="findbox.searchValue" class="w-80 m-2" placeholder="输入试卷名进行搜索..." suffix-icon="el-icon-search" size="small" />
+          </div>
+        </div>
+        <div class="middlebox-right">
+          <div class="middlebox-right-title">共有<span class="middlebox-right-num">70</span>套</div>
+        </div>
+      </div>
+    </div>
+    <div class="bottombox">
+      <div class="bottombox-list">
+        <div class="paperlist">
+          <div class="paperlist-name">
+            <span class="paperlist-name-tag">语文</span>
+            <span class="paperlist-name-title">全客观题(新)</span>
+          </div>
+          <div class="paperlist-info">
+            <span class="paperlist-info-title">
+              适用学段:
+              <span class="paperlist-info-content">小学</span>
+            </span>
+            <span class="paperlist-info-title">
+              适用年级:
+              <span class="paperlist-info-content">一年级</span>
+            </span>
+            <span class="paperlist-info-title">
+              题量:
+              <span class="paperlist-info-content">15</span>
+            </span>
+            <span class="paperlist-info-title">
+              排序方式:
+              <span class="paperlist-info-content">题型排序</span>
+            </span>
+            <span class="paperlist-info-title">
+              更新时间:
+              <span class="paperlist-info-content">2022-09-20 17:41:04 </span>
+            </span>
+          </div>
+          <div class="paperlist-tools">
+            <span class="paperlist-tools-download">
+              <svg class="icon" aria-hidden="true">
+                <use xlink:href="#icon-xiazai"></use>
+              </svg>
+              <span class="paperlist-tools-download-title">下载</span>
+            </span>
+            <span class="paperlist-tools-delete">
+              <svg class="icon" aria-hidden="true">
+                <use xlink:href="#icon-shanchutianchong"></use>
+              </svg>
+              <span class="paperlist-tools-download-title">删除</span>
+            </span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import { ref } from 'vue'
+export default {
+  setup () {
+    let activeNames = ref([])
+    let findbox = ref({
+      tagValue: '',
+      searchValue: ''
+    })
+    const options = [
+      {
+        value: 'Option1',
+        label: 'Option1',
+      },
+      {
+        value: 'Option2',
+        label: 'Option2',
+      },
+      {
+        value: 'Option3',
+        label: 'Option3',
+      },
+      {
+        value: 'Option4',
+        label: 'Option4',
+      },
+      {
+        value: 'Option5',
+        label: 'Option5',
+      },
+    ]
+    return { activeNames, findbox, options, }
+  },
+}
+</script>
+<style scoped>
+.examinationbox {
+  width: 100%;
+  line-height: 20px;
+}
+.header-filter,
+.middlebox {
+  /* width: 100%; */
+  /* background-color: #fff; */
+  margin: 10px 20px;
+}
+.middlebox {
+  background-color: #fff;
+}
+.middlebox-content {
+  display: flex;
+}
+.middlebox-left {
+  width: 50%;
+  text-align: left;
+  padding-left: 1%;
+  font-size: 14px;
+  display: flex;
+}
+.middlebox-left-tag {
+  width: 30%;
+}
+.middlebox-left-serach {
+  width: 65%;
+}
+.middlebox-right {
+  width: 50%;
+  text-align: right;
+  font-size: 16px;
+  line-height: 48px;
+  padding-right: 1%;
+}
+.middlebox-right-num {
+  font-size: 18px;
+  color: #eb4d4b;
+}
+.bottombox {
+  background-color: #fff;
+  margin: 10px 20px;
+}
+.paperlist {
+  height: 90px;
+  background: #fff;
+  margin-bottom: 10px;
+  padding-left: 10px;
+  align-items: flex-start;
+  cursor: pointer;
+  width: 100%;
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+.paperlist-name {
+  font-size: 20px;
+  font-weight: 700;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.paperlist-name-tag {
+  font-size: 12px;
+  padding: 1px 10px;
+  border-radius: 5px;
+  color: #fff;
+  background: #15a06c;
+  margin: 0 10px;
+}
+.paperlist-name-title {
+  margin-left: 8px;
+}
+.paperlist-info {
+  margin-top: 18px;
+}
+.paperlist-info-title {
+  border-right: 2px solid #f3f3f3;
+  font-size: 12px;
+  padding: 0 10px;
+}
+.paperlist-info-content {
+  font-weight: 700;
+  color: #70b1e7;
+}
+.bottombox-list {
+  width: 100%;
+}
+.paperlist-tools {
+  position: absolute;
+  height: 100%;
+  right: 0px;
+  top: 0;
+  font-size: 14px;
+  color: #767676;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.paperlist-tools-download,
+.paperlist-tools-delete {
+  margin-right: 30px;
+  /* position: absolute; */
+  height: 100%;
+  /* right: 50px; */
+  top: 0;
+  font-size: 14px;
+  color: #767676;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.paperlist-tools-delete {
+  margin-right: 30px;
+}
+.paperlist-tools-download-title {
+  width: 35px;
+}
+.icon {
+  width: 1.3em;
+  height: 1.3em;
+  vertical-align: -0.4em;
+  fill: currentColor;
+  overflow: hidden;
+  margin-right: 5px;
+  margin-left: 0px;
+}
+</style>
+<style>
+.header-filter .el-collapse-item__header {
+  padding-left: 1%;
+  font-size: 16px;
+  font-weight: bold;
+}
+</style>

+ 149 - 87
TEAMModelBI/ClientApp/src/view/participation/index.vue

@@ -217,28 +217,29 @@
       <el-tab-pane :label="$t(`schoolManages.redactGrading`)">
         <SetSchool :schoolData="studyPhase" ref="setSchoolData"></SetSchool>
       </el-tab-pane>
-      <!-- <el-tab-pane :label="$t(`schoolManages.redactServe`)">
-                <Impower :schoolCode="studyPhase"></Impower>
-            </el-tab-pane>
-            <el-tab-pane :label="$t(`schoolManages.redactSerial`)">
-                <Classpower :schoolCode="studyPhase"></Classpower>
-            </el-tab-pane> -->
+      <el-tab-pane label="试卷资源">
+        <Exammination></Exammination>
+      </el-tab-pane>
     </el-tabs>
   </div>
   <!--编辑学校页面end-->
 </template>
 <script>
 import { reactive, ref, getCurrentInstance, toRef, onMounted, watch } from 'vue'
-import option from '@/static/region.json'
+import option_cn from '@/static/regions/region_cn.json'
+import option_gl from '@/static/regions/region_gl.json'
 import { useStore } from 'vuex'
 import { ElMessage, ElLoading, ElMessageBox } from 'element-plus'
 import { useRouter } from 'vue-router'
 import jwt_decode from 'jwt-decode'
 import SetSchool from './setPhase.vue'
-const optionsData = option
+import Exammination from './examination.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
 export default {
   components: {
     SetSchool,
+    Exammination
   },
   setup () {
     let { proxy } = getCurrentInstance()
@@ -284,7 +285,7 @@ export default {
       scale: 0,
     })
     let originalData = ref([])
-    const options = option
+    const options = optionsData
     const props = {
       value: 'name',
       label: 'name',
@@ -401,7 +402,7 @@ export default {
           }
         }
         console.log(res)
-        res.state == 200 ? (tableData.value.push(...res.schoolAssists), (originalData.value = res.schoolAssists), (loading.value = false)) : ''
+        res.state == 200 ? (tableData.value.push(...res.schoolAssists), (originalData.value = res.schoolAssists), (loading.value = false), tableNexttoken.value = res.continuationToken) : ''
       })
     }
     //点击学校列表,详情
@@ -441,42 +442,103 @@ export default {
       }
     }
     //地区选择
-    function areaSelctChange (value, model) {
+    async function areaSelctChange (value, model) {
       console.log(value, model, '触发')
-      // loading.value = true
-      // console.log(value)
-      // let data = option
-      // if (model === 'province') {
-      //   //传输下一级的数据给select
-      //   let cityData = data.filter((item) => {
-      //     return item.name === value
-      //   })
-      //   cityOptions.value.cityInfo = cityData[0].children
-      //   //遍历list
-      //   let schoolData = originalData.value.filter((items) => {
-      //     return items.province === value
-      //   })
-      //   tableData.value = schoolData
-      //   console.log(schoolData, tableData.value)
-      // } else if (model === 'city') {
-      //   let distData = cityOptions.value.cityInfo.filter((item) => {
-      //     return item.name === value
-      //   })
-      //   distOptions.value.distInfo = distData[0].children
-      //   let provinceData = provinceOptions.value.provinceValue
-      //   let schoolData = originalData.value.filter((items) => {
-      //     return items.city === value && items.province === provinceData
-      //   })
-      //   tableData.value = schoolData
-      // } else if (model === 'dist') {
-      //   let provinceData = provinceOptions.value.provinceValue
-      //   let cityData = cityOptions.value.cityValue
-      //   let schoolData = originalData.value.filter((items) => {
-      //     return items.city === cityData && items.province === provinceData && items.dist === value
-      //   })
-      //   tableData.value = schoolData
-      // }
-      // loading.value = false
+      loading.value = true
+      let user = jwt_decode(JSON.parse(localStorage.getItem('id_token')))
+      console.log(user, '人员')
+      let roleA = ''
+      if (user.roles.length > 1) {
+        user.roles.includes('admin') ? roleA = 'admin' :
+          user.roles.includes('leader') ? roleA = 'leader' :
+            user.roles.includes('assist') ? roleA = 'assist' :
+              user.roles.includes('sales') ? roleA = 'sales' :
+                user.roles.includes('rdc') ? roleA = 'rdc' : ''
+      } else {
+        roleA = user.roles[0]
+      }
+      var schoolListDatas = []
+      var nextPageToken = ''
+      var regionsData = optionsData
+      if (model === 'province') {
+        //传输下一级的数据给select
+        let cityData = regionsData.filter((item) => {
+          return value.includes(item.name)
+        })
+        cityOptions.value.cityInfo = cityData[0].children
+        let textNums = value.indexOf('省') !== -1 ? value.indexOf('省') : value.indexOf('自治区') !== -1 ? value.indexOf('自治区') : value.indexOf('市') !== -1 ? value.indexOf('市') : value.indexOf('特别行政区') !== -1 ? value.indexOf('特别行政区') : ''
+        let disposeText = value.substr(0, textNums)
+        console.log(textNums, disposeText, '位置')
+        let data = roleA === 'admin' || roleA === 'leader' ? { province: disposeText } : { province: disposeText, tmdId: user.tmdId }
+        await proxy.$api.getSchooldata(data).then((res) => {
+          console.log(res, '筛选结果')
+          // res.state === 200 ? tableData.value=res.schoolAssists:''
+          res.state === 200 ? (schoolListDatas = res.schoolAssists, selectValue.value.province = disposeText, nextPageToken = res.continuationToken) : ''
+        }).catch((error) => {
+          ElMessage.error('API异常,数据 省 筛选失败')
+        })
+        // tableData.value = schoolData
+        // console.log(schoolData, tableData.value)
+      } else if (model === 'city') {
+        let distData = cityOptions.value.cityInfo.filter((item) => {
+          return value.includes(item.name)
+        })
+        distOptions.value.distInfo = distData[0].children
+        // let provinceData = provinceOptions.value.provinceValue
+        // let schoolData = originalData.value.filter((items) => {
+        //   return value.includes(items.city) && provinceData.includes(items.province)
+        //   // return items.city === value && items.province === provinceData
+        // })
+        // tableData.value = schoolData
+        let cityNums = value.indexOf('市') !== -1 && value !== '直辖市' ? value.indexOf('市') : value.indexOf('县') !== -1 ? value.indexOf('县') : value.indexOf('自治州') !== -1 ? value.indexOf('自治州') : value.indexOf('直辖市') !== -1 ? value.length : ''
+        let disposeText = value.substr(0, cityNums)
+        console.log(cityNums, disposeText, '位置')
+        // let data = { province: selectValue.value.province ? selectValue.value.province : '', city: disposeText }
+        let data = roleA === 'admin' || roleA === 'leader' ? { province: selectValue.value.province ? selectValue.value.province : '', city: disposeText } : { province: selectValue.value.province ? selectValue.value.province : '', city: disposeText, tmdId: user.tmdId }
+        await proxy.$api.getSchooldata(data).then((res) => {
+          res.state === 200 ? (schoolListDatas = res.schoolAssists, selectValue.value.city = disposeText, nextPageToken = res.continuationToken) : ''
+        }).catch((error) => {
+          ElMessage.error('API异常,数据 市/县 筛选失败')
+        })
+      } else if (model === 'dist') {
+        let provinceData = provinceOptions.value.provinceValue
+        let cityData = cityOptions.value.cityValue
+        console.log(cityData, provinceData, '进入到地区选择')
+        let distNums = value.indexOf('区') !== -1 && value.length > 2 ? value.indexOf('区') : value.indexOf('县') !== -1 ? value.indexOf('县') : value.indexOf('市') !== -1 ? value.indexOf('市') : value.indexOf('直辖市') !== -1 || value.indexOf('天府新区') !== -1 ? value.length : ''
+        let disposeText = value.substr(0, distNums)
+        console.log(distNums, disposeText, '位置')
+        // let data = { province: selectValue.value.province ? selectValue.value.province : '', city: selectValue.value.city ? selectValue.value.city : '', dist: disposeText }
+        let data = roleA === 'admin' || roleA === 'leader' ? { province: selectValue.value.province ? selectValue.value.province : '', city: selectValue.value.city ? selectValue.value.city : '', dist: disposeText } : { province: selectValue.value.province ? selectValue.value.province : '', city: selectValue.value.city ? selectValue.value.city : '', dist: disposeText, tmdId: user.tmdId }
+        await proxy.$api.getSchooldata(data).then((res) => {
+          res.state === 200 ? (schoolListDatas = res.schoolAssists, nextPageToken = res.continuationToken) : ''
+        }).catch((error) => {
+          ElMessage.error('API异常,数据 地区 筛选失败')
+        })
+      }
+      //统一处理
+      console.log(schoolListDatas, '处理前的')
+      for (let i in schoolListDatas) {
+        schoolListDatas[i].serviceData = []
+        if (schoolListDatas[i].assists) {
+          schoolListDatas[i].assisName = ''
+          schoolListDatas[i].location = schoolListDatas[i].dist !== null ? schoolListDatas[i].province + schoolListDatas[i].city + schoolListDatas[i].dist : schoolListDatas[i].province + schoolListDatas[i].city
+          let datas = schoolListDatas[i].assists
+          for (let y in datas) {
+            schoolListDatas[i].assisName = schoolListDatas[i].assisName + datas[y].tmdName + ','
+          }
+        }
+        if (schoolListDatas[i].service.length > 0) {
+          schoolListDatas[i].service.forEach((x) => {
+            for (let m in patternIcon.value) {
+              patternIcon.value[m].key === x ? schoolListDatas[i].serviceData.push(patternIcon.value[m]) : ''
+            }
+          })
+        }
+      }
+      tableData.value = schoolListDatas
+      tableData.value.forEach((item) => { item.areaName = ''; areaSelect.value.data.forEach((itema) => { item.areaId === itema.id ? item.areaName = itema.name : '' }) })
+      tableNexttoken.value = nextPageToken
+      loading.value = false
     }
     //学校详情 close
     function schoolClose () {
@@ -686,49 +748,49 @@ export default {
     }
     function datascroll () {
       console.log('触发了')
-      // loading.value = true
-      // let data = { contToken: tableNexttoken.value, province: selectValue.value.province, city: selectValue.value.city, dist: selectValue.value.dist }
-      // if (tableNexttoken.value === null) {
-      //   ElMessage.success('已经到最底了')
-      //   setTimeout(function () { loading.value = false }, 500);
-      //   return
-      // }
-      // proxy.$api.getSchooldata(data).then((res) => {
-      //   console.log(res, '查询到下一页数据了')
-      //   if (res.state === 200) {
-      //     for (let i in res.schoolAssists) {
-      //       res.schoolAssists[i].serviceData = []
-      //       if (res.schoolAssists[i].assists) {
-      //         res.schoolAssists[i].assisName = ''
-      //         res.schoolAssists[i].location = res.schoolAssists[i].dist !== null ? res.schoolAssists[i].province + res.schoolAssists[i].city + res.schoolAssists[i].dist : res.schoolAssists[i].province + res.schoolAssists[i].city
-      //         let datas = res.schoolAssists[i].assists
-      //         for (let y in datas) {
-      //           res.schoolAssists[i].assisName = res.schoolAssists[i].assisName + datas[y].tmdName + ','
-      //         }
-      //       }
-      //       if (res.schoolAssists[i].service.length > 0) {
-      //         res.schoolAssists[i].service.forEach((x) => {
-      //           for (let m in patternIcon.value) {
-      //             patternIcon.value[m].key === x ? res.schoolAssists[i].serviceData.push(patternIcon.value[m]) : ''
-      //           }
-      //         })
-      //       }
-      //     }
-      //   }
-      //   tableData.value.push(...res.schoolAssists)
-      //   tableData.value.forEach((item) => { item.areaName = ''; areaSelect.value.data.forEach((itema) => { item.areaId === itema.id ? item.areaName = itema.name : '' }) })
-      //   tablesccnt.value = res.scCnt
-      //   tableNexttoken.value = res.continuationToken
-      // }).catch((error) => {
-      //   ElMessage.error('API异常,获取更多学校数据失败')
-      // })
-      // setTimeout(function () { loading.value = false }, 800);
+      loading.value = true
+      let data = { contToken: tableNexttoken.value, province: selectValue.value.province, city: selectValue.value.city, dist: selectValue.value.dist }
+      if (tableNexttoken.value === null) {
+        ElMessage.success('已经到最底了')
+        setTimeout(function () { loading.value = false }, 500);
+        return
+      }
+      proxy.$api.getSchooldata(data).then((res) => {
+        console.log(res, '查询到下一页数据了')
+        if (res.state === 200) {
+          for (let i in res.schoolAssists) {
+            res.schoolAssists[i].serviceData = []
+            if (res.schoolAssists[i].assists) {
+              res.schoolAssists[i].assisName = ''
+              res.schoolAssists[i].location = res.schoolAssists[i].dist !== null ? res.schoolAssists[i].province + res.schoolAssists[i].city + res.schoolAssists[i].dist : res.schoolAssists[i].province + res.schoolAssists[i].city
+              let datas = res.schoolAssists[i].assists
+              for (let y in datas) {
+                res.schoolAssists[i].assisName = res.schoolAssists[i].assisName + datas[y].tmdName + ','
+              }
+            }
+            if (res.schoolAssists[i].service.length > 0) {
+              res.schoolAssists[i].service.forEach((x) => {
+                for (let m in patternIcon.value) {
+                  patternIcon.value[m].key === x ? res.schoolAssists[i].serviceData.push(patternIcon.value[m]) : ''
+                }
+              })
+            }
+          }
+        }
+        tableData.value.push(...res.schoolAssists)
+        tableData.value.forEach((item) => { item.areaName = ''; areaSelect.value.data.forEach((itema) => { item.areaId === itema.id ? item.areaName = itema.name : '' }) })
+        tablesccnt.value = res.scCnt
+        tableNexttoken.value = res.continuationToken
+      }).catch((error) => {
+        ElMessage.error('API异常,获取更多学校数据失败')
+      })
+      setTimeout(function () { loading.value = false }, 800);
     }
-    // watch(scrollHeight, (newdata) => {
-    //   if (scrollHeight.value < 0) {
-    //     debounce(datascroll, 500)
-    //   }
-    // })
+    watch(scrollHeight, (newdata) => {
+      if (scrollHeight.value < 0) {
+        debounce(datascroll, 500)
+      }
+    })
     getAllschool()
     getAllassists()
     return {

+ 23 - 16
TEAMModelBI/ClientApp/src/view/participation/setPhase.vue

@@ -1325,7 +1325,7 @@ export default {
 .phasebox {
   width: 100%;
   line-height: 20px;
-  height: 87vh;
+  height: 89vh;
   background-color: #fff;
 }
 
@@ -1335,7 +1335,7 @@ export default {
   text-align: left;
   display: inline-block;
   line-height: 20px;
-  height: 87vh;
+  height: 89vh;
   vertical-align: top;
 }
 
@@ -1346,7 +1346,7 @@ export default {
 .center-pane {
   width: 50%;
   display: inline-block;
-  height: 87vh;
+  height: 89vh;
   border-right: 1px solid #ccc;
   text-align: left;
   overflow-y: auto;
@@ -2296,7 +2296,7 @@ export default {
 }
 
 .settimebox {
-  overflow: hidden;
+  overflow: auto;
   height: 72vh;
 }
 
@@ -2358,16 +2358,24 @@ export default {
   font-weight: 600;
   color: #bdc3c7;
 }
-
 @media screen and (max-width: 1367px) {
+  .settime-icon div {
+    margin-bottom: 50%;
+  }
   .settimebox .el-card__body {
     width: 200px;
   }
-}
-
-@media screen and (max-width: 1367px) {
-  .settime-icon div {
-    margin-bottom: 50%;
+  /* .redactbox {
+    height: 84vh;
+  } */
+  .school-form-name {
+    width: 45% !important;
+  }
+  .school-form-badge {
+    width: 23vw !important;
+  }
+  .school-form-size {
+    width: 55% !important;
   }
 }
 
@@ -2376,13 +2384,12 @@ export default {
   .subjectbox {
     width: 98% !important;
   }
-
-  .phasebox {
-    height: 78vh !important;
-  }
-
+  .phasebox,
   .center-pane {
-    height: 79vh !important;
+    height: 86vh !important;
+  }
+  .settimebox {
+    height: 77vh !important;
   }
 }
 </style>

+ 7 - 10
TEAMModelBI/ClientApp/src/view/schoolServe/setschool.vue

@@ -1391,7 +1391,7 @@ export default {
 .phasebox {
   width: 100%;
   line-height: 20px;
-  height: 87vh;
+  height: 89vh;
   background-color: #fff;
 }
 
@@ -1401,7 +1401,7 @@ export default {
   text-align: left;
   display: inline-block;
   line-height: 20px;
-  height: 87vh;
+  height: 89vh;
   vertical-align: top;
 }
 
@@ -1412,7 +1412,7 @@ export default {
 .center-pane {
   width: 50%;
   display: inline-block;
-  height: 87vh;
+  height: 89vh;
   border-right: 1px solid #ccc;
   text-align: left;
   overflow-y: auto;
@@ -2383,8 +2383,8 @@ export default {
 }
 
 .settimebox {
-  overflow: hidden;
-  height: 72vh;
+  overflow: atuo;
+  height: 77vh;
 }
 
 .settimebox:hover {
@@ -2464,12 +2464,9 @@ export default {
     width: 98% !important;
   }
 
-  .phasebox {
-    height: 78vh !important;
-  }
-
+  .phasebox,
   .center-pane {
-    height: 79vh !important;
+    height: 86vh !important;
   }
 }
 </style>

+ 19 - 11
TEAMModelBI/Controllers/BINormal/BatchAreaController.cs

@@ -110,7 +110,7 @@ namespace TEAMModelBI.Controllers.BINormal
                 //    table = _azureStorage.GetCloudTableClient(BIConst.Global).GetTableReference("IESLogin");
                 //}
 
-                StringBuilder areaSql = new($"select c.id,c.code,c.pk,c.name,c.provCode,c.provName,c.cityCode,c.cityName,c.standard,c.standardName,c.institution from c");
+                StringBuilder areaSql = new($"select c.id,c.code,c.pk,c.name,c.provCode,c.provName,c.cityCode,c.cityName,c.standard,c.standardName,c.institution,c.updateTime,c.quoteId from c");
                 if (!string.IsNullOrEmpty($"{id}") && string.IsNullOrEmpty($"{name}"))
                     areaSql.Append($" where c.id='{id}'");
 
@@ -243,7 +243,7 @@ namespace TEAMModelBI.Controllers.BINormal
 
                 //区级的ID
                 string areaId = Guid.NewGuid().ToString();
-                Area addArea = new Area()
+                Area addArea = new()
                 {
                     id = areaId,
                     code = $"Base-Area",
@@ -254,7 +254,8 @@ namespace TEAMModelBI.Controllers.BINormal
                     cityName = $"{cityName}",
                     standard = $"{standard}",
                     standardName = $"{standardName}",
-                    institution = $"{institution}"
+                    institution = $"{institution}",
+                    quoteId = $"{_oldId}"
                 };
 
                 #region  区级管理员
@@ -651,7 +652,6 @@ namespace TEAMModelBI.Controllers.BINormal
                 //}
                 var table = tableClient.GetTableReference("IESLogin");
 
-
                 var responseSet = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemStreamAsync($"{_oldId}", new PartitionKey("AreaSetting"));
                 if (responseSet.Status == 200)
                 {
@@ -662,9 +662,9 @@ namespace TEAMModelBI.Controllers.BINormal
                 }
 
                 //保存引用记录
-                //await table.SaveOrUpdate<AreaQuoteRecord>(new AreaQuoteRecord() { PartitionKey = "QuoteRecord", RowKey = $"{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}", areaId = $"{_oldId}", quoteId = $"{_newId}", quoteName = $"{newName}", standard = $"{_newStandard}" });
+                await table.SaveOrUpdate<AreaQuoteRecord>(new AreaQuoteRecord() { PartitionKey = "QuoteRecord", RowKey = $"{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}", areaId = $"{_oldId}", quoteId = $"{_newId}", quoteName = $"{newName}", standard = $"{_newStandard}" });
 
-                List<string> abilityIds = new List<string>();  //册别的ID集合
+                List<string> abilityIds = new();  //册别的ID集合
 
                 //查询册别信息
                 await foreach (var tempAbility in cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Ability>(queryText: $"select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Ability-{_oldStandard}") }))
@@ -677,7 +677,7 @@ namespace TEAMModelBI.Controllers.BINormal
                     var sresponse = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").DeleteItemsStreamAsync(abilityIds, $"Ability-{_oldStandard}");
                 }
 
-                List<string> abilityTaskIds = new List<string>();  //章节ID集合
+                List<string> abilityTaskIds = new();  //章节ID集合
                 await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<AbilityTask>(queryText: $"select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"AbilityTask-{_oldStandard}") }))
                 {
                     abilityTaskIds.Add(item.id);   //查询出来的章节信息ID添加到战绩集合
@@ -688,8 +688,8 @@ namespace TEAMModelBI.Controllers.BINormal
                     var sresponse = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").DeleteItemsStreamAsync(abilityTaskIds, $"AbilityTask-{_oldStandard}");
                 }
 
-                List<Task<ItemResponse<Ability>>> abilities = new List<Task<ItemResponse<Ability>>>();      //存储册别数据
-                List<Task<ItemResponse<AbilityTask>>> abilityTasks = new List<Task<ItemResponse<AbilityTask>>>();  //存储章节
+                List<Task<ItemResponse<Ability>>> abilities = new();      //存储册别数据
+                List<Task<ItemResponse<AbilityTask>>> abilityTasks = new();  //存储章节
 
                 //查询要复制区域的能力标准点 
                 await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Ability>(queryText: $"select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Ability-{_newStandard}") }))
@@ -725,7 +725,7 @@ namespace TEAMModelBI.Controllers.BINormal
                 }
                 catch
                 {
-                    return Ok(new { state = 200, msg = "创区成功,能力标准点复制失败,遗留数据影响!" });
+                    return Ok(new { state = 200, msg = "能力标准点复制失败,遗留数据影响!" });
                 }
 
                 try
@@ -764,7 +764,7 @@ namespace TEAMModelBI.Controllers.BINormal
                 }
                 catch
                 {
-                    return Ok(new { state = 200, msg = "创区成功,能力标准创建成功,微能力点复制失败,遗留数据影响!" });
+                    return Ok(new { state = 200, msg = "能力标准创建成功,微能力点复制失败,遗留数据影响!" });
                 }
 
                 StandardFile saveFile = new();
@@ -821,6 +821,12 @@ namespace TEAMModelBI.Controllers.BINormal
                     tempSetting = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").CreateItemAsync(saveSetting, new PartitionKey($"AreaSetting"));  //需要删除原来的区域设置数据在进行添加
                 }
 
+                //修改切换区级能力引用id
+                Area area = new();
+                area = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<Area>($"{_oldId}", new PartitionKey("Base-Area"));
+                area.quoteId = $"{_newId}";
+                await cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").ReplaceItemAsync<Area>(area, area.id, new PartitionKey(area.code));
+
                 //发送消息分区键
                 string partitionCode = "DelBeforeCopyAbility-mark";
                 //v2通知
@@ -1312,6 +1318,8 @@ namespace TEAMModelBI.Controllers.BINormal
             public string standardName { get; set; }
             public string institution { get; set; }
             public int schoolCount { get; set; }
+            public long updateTime { get; set; }
+            public string quoteId { get; set; } = null;
             public bool cutArea { get; set; } = false;
             public List<AreaQuoteRecord> aquoteRec { get; set; } = new List<AreaQuoteRecord>();
         }

+ 3 - 3
TEAMModelBI/Controllers/BISchool/SchoolController.cs

@@ -881,10 +881,10 @@ namespace TEAMModelBI.Controllers.BISchool
                     foreach (var school in schools)
                     {
                         SchoolTeacher schoolTeacher = null;
-                        var existArea = teacher.schools.Find(f => f.schoolId.Equals($"{school.id}"));
-                        if (existArea == null)
+                        var existSchool = teacher.schools.Find(f => f.schoolId.Equals($"{school.id}"));
+                        if (existSchool == null)
                         {
-                            teacher.schools.Add(new Teacher.TeacherSchool { schoolId = $"{school.id}", name = $"{school.id}", status = "join", time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), picture = string.IsNullOrEmpty($"{school.picture}") ? "" : $"{school.picture}", areaId = string.IsNullOrEmpty($"{school.areaId}") ? "" : $"{school.areaId}" });
+                            teacher.schools.Add(new Teacher.TeacherSchool { schoolId = $"{school.id}", name = $"{school.name}", status = "join", time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), picture = string.IsNullOrEmpty($"{school.picture}") ? "" : $"{school.picture}", areaId = string.IsNullOrEmpty($"{school.areaId}") ? "" : $"{school.areaId}" });
                         }
 
                         var response = await cosmosClient.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync($"{tmdId}", new PartitionKey($"Teacher-{school.id}"));

+ 52 - 20
TEAMModelBI/Controllers/BITest/TestController.cs

@@ -53,6 +53,7 @@ using Azure.Storage.Blobs;
 using Azure.Storage.Blobs.Specialized;
 using System.Web;
 using Azure.Storage.Sas;
+using DocumentFormat.OpenXml.Drawing.Diagrams;
 
 namespace TEAMModelBI.Controllers.BITest
 {
@@ -1478,36 +1479,67 @@ namespace TEAMModelBI.Controllers.BITest
         {
 
             List<Task<CopyFromUriOperation>> filelist = new List<Task<CopyFromUriOperation>>();
-            var azureClient = _azureStorage.GetBlobContainerClient($"0-public");//获取容器连接地址
+            //var azureClient = _azureStorage.GetBlobContainerClient($"0-public");//获取容器连接地址
+
+            ////查询目录下所有容器路径
+            //await foreach (BlobItem blobItem in azureClient.GetBlobsAsync(BlobTraits.None, BlobStates.None, $"TestMP4Max/"))
+            //{
+            //    string newurl = $"{blobItem.Name}".Replace($"/SourceFile/", $"/SourceFiles/");//替换成新的容器路径
+            //    var urlSas = _azureStorage.GetBlobSAS($"0-public", blobItem.Name, BlobSasPermissions.Read | BlobSasPermissions.List);   //获取容器sas和有效期
+            //    //await azureClient.GetBlobClient(newurl).StartCopyFromUriAsync(new Uri(urlSas));
+            //    filelist.Add(azureClient.GetBlobClient(newurl).StartCopyFromUriAsync(new Uri(urlSas)));
+            //    //await azureClient.GetBlobClient(newurl).SyncCopyFromUriAsync(new Uri(urlSas));  //添加复制文件到集合执行复制操作
+            //}
+            //if (filelist.Count <= 256)
+            //{
+            //    await Task.WhenAll(filelist);
+            //}
+            //else
+            //{
+            //    int pages = (filelist.Count + 255) / 256;
+            //    for (int i = 0; i < pages; i++)
+            //    {
+            //        List<Task<CopyFromUriOperation>> rspBlobCopyInfos = filelist.Skip((i) * 256).Take(256).ToList();
+            //        await Task.WhenAll(rspBlobCopyInfos);
+            //    }
+            //}
+
+            var azureClient = _azureStorage.GetBlobContainerClient($"1636016499");//获取容器连接地址
 
             //查询目录下所有容器路径
-            await foreach (BlobItem blobItem in azureClient.GetBlobsAsync(BlobTraits.None, BlobStates.None, $"TestMP4Max/"))
+            await foreach (BlobItem blobItem in azureClient.GetBlobsAsync(BlobTraits.None, BlobStates.None, $"doc"))
             {
-                string newurl = $"{blobItem.Name}".Replace($"/SourceFile/", $"/SourceFiles/");//替换成新的容器路径
-                var urlSas = _azureStorage.GetBlobSAS($"0-public", blobItem.Name, BlobSasPermissions.Read | BlobSasPermissions.List);   //获取容器sas和有效期
+                string newurl = $"{blobItem.Name}".Replace($"doc/", $"/SourceFiles/");//替换成新的容器路径
+                var urlSas = _azureStorage.GetBlobSAS($"1636016499", blobItem.Name, BlobSasPermissions.Read | BlobSasPermissions.List);   //获取容器sas和有效期
                 //await azureClient.GetBlobClient(newurl).StartCopyFromUriAsync(new Uri(urlSas));
-                filelist.Add(azureClient.GetBlobClient(newurl).StartCopyFromUriAsync(new Uri(urlSas)));
+                await azureClient.GetBlobClient(newurl).StartCopyFromUriAsync(new Uri(urlSas));
                 //await azureClient.GetBlobClient(newurl).SyncCopyFromUriAsync(new Uri(urlSas));  //添加复制文件到集合执行复制操作
-
-            }
-            if (filelist.Count <= 256)
-            {
-                await Task.WhenAll(filelist);
             }
-            else
-            {
-                int pages = (filelist.Count + 255) / 256;
-                for (int i = 0; i < pages; i++)
-                {
-                    List<Task<CopyFromUriOperation>> rspBlobCopyInfos = filelist.Skip((i) * 256).Take(256).ToList();
-                    await Task.WhenAll(rspBlobCopyInfos);
-                }
-            }
-
 
             return Ok(new { state = 200 , filelist });
         }
 
+        [HttpPost("test-copy-file")]
+        public async Task<IActionResult> TestCaopyFile()
+        {
+            string blobName = "cswznb";
+            string oldFile = "https://teammodeltest.blob.core.chinacloudapi.cn/cswznb/survey%2Fd011c05b-c009-0a53-428f-b871a58092c7%2Findex.json";//"https://teammodeltest.blob.core.chinacloudapi.cn/1636016499/yxpt%2Fstandard2%2FTEAMModelOS%E6%95%B0%E6%8D%AE%E5%BA%93.doc";
+            string oldId = "survey";
+            string newId = "survey1";
+
+            List<Task<CopyFromUriOperation>> filelist = new();   //可复制256M以上文件
+            var set = await BatchCopyFileService.SingleCopyFile(_azureStorage, blobName, oldFile, oldId, newId);
+
+            //var azureClient = _azureStorage.GetBlobContainerClient($"{blobName}");//获取容器连接地址
+            //string newurl = oldFile.Substring(oldFile.IndexOf($"{blobName}/") + $"{blobName}/".Length).Replace($"{oldId}", $"{newId}");//替换成新的容器路径
+            //string oldFileName = oldFile.Substring(oldFile.IndexOf($"{blobName}/") + $"{blobName}/".Length);
+            //var urlSas = _azureStorage.GetBlobSAS($"{blobName}", $"{HttpUtility.UrlDecode(oldFileName)}", BlobSasPermissions.Read | BlobSasPermissions.List);   //获取容器sas和有效期
+            ////var respCopy =  azureClient.GetBlobClient(HttpUtility.UrlDecode(newurl)).SyncCopyFromUri(new Uri(urlSas));    //可复制256M以下文件
+            //var respCopy1 = await azureClient.GetBlobClient(HttpUtility.UrlDecode(newurl)).StartCopyFromUriAsync(new Uri(urlSas));    //可复制256M以上文件
+
+            return Ok(new { state = 200 });
+        }
+
         public class linqTest
         {
             public string id { get; set; }

+ 3 - 3
TEAMModelBI/TEAMModelBI.csproj

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

+ 1 - 1
TEAMModelOS.SDK/Models/Cosmos/BI/AreaQuoteRecord.cs

@@ -11,7 +11,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.BI
     /// <summary>
     /// 区域引用记录
     /// </summary>
-    [TableName(Name = "IESLogin")]
+    [TableName(Name = "BIRecord")]
     public class AreaQuoteRecord : TableEntity
     {
         public string areaId { get; set; }

+ 4 - 1
TEAMModelOS.SDK/Models/Cosmos/Normal/Area.cs

@@ -44,6 +44,9 @@ namespace TEAMModelOS.SDK.Models
         public string institution { get; set; }
         public long updateTime { get; set; }
 
-
+        /// <summary>
+        /// 引用id
+        /// </summary>
+        public string quoteId { get; set; } = null;
     }
 }

+ 30 - 0
TEAMModelOS.SDK/Models/Service/BatchCopyFileService.cs

@@ -9,6 +9,7 @@ using Azure;
 using Azure.Storage.Sas;
 using System.Linq;
 using Azure.Storage.Blobs.Specialized;
+using System.Web;
 
 namespace TEAMModelOS.SDK.Models.Service
 {
@@ -81,8 +82,37 @@ namespace TEAMModelOS.SDK.Models.Service
                 await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-Batch-CopyFile \n {ex.Message}\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
                 return -1;
             }
+        }
 
+        /// <summary>
+        /// 修复研修平台多人使用个账户,分开账户复制文件时使用
+        /// </summary>
+        /// <param name="_azureStorage"></param>
+        /// <param name="blobName"></param>
+        /// <param name="oldFile"></param>
+        /// <param name="oldId"></param>
+        /// <param name="newId"></param>
+        /// <returns></returns>
+        public static async Task<int> SingleCopyFile(AzureStorageFactory _azureStorage, string blobName, string oldFile, string oldId, string newId)
+        {
+            try
+            {
+                var azureClient = _azureStorage.GetBlobContainerClient($"{blobName}");//获取容器连接地址
+                string newurl = oldFile.Substring(oldFile.IndexOf($"{blobName}/") + $"{blobName}/".Length).Replace($"{oldId}", $"{newId}");//替换成新的容器路径
+                string oldFileName = oldFile.Substring(oldFile.IndexOf($"{blobName}/") + $"{blobName}/".Length);
+                var urlSas = _azureStorage.GetBlobSAS($"{blobName}", $"{HttpUtility.UrlDecode(oldFileName)}", BlobSasPermissions.Read | BlobSasPermissions.List);   //获取容器sas和有效期
+                //var respCopy =  azureClient.GetBlobClient(HttpUtility.UrlDecode(newurl)).SyncCopyFromUri(new Uri(urlSas));    //可复制256M以下文件
+                var respCopy1 = await azureClient.GetBlobClient(HttpUtility.UrlDecode(newurl)).StartCopyFromUriAsync(new Uri(urlSas));    //可复制256M以上文件
 
+                if (!string.IsNullOrEmpty($"{respCopy1.Id}"))
+                    return 200;
+                else
+                    return 400;
+            }
+            catch(Exception ex)
+            {
+                return 400;
+            }
         }
 
     }

+ 61 - 6
TEAMModelOS.SDK/Models/Service/Common/ActivityStudentService.cs

@@ -52,8 +52,8 @@ namespace TEAMModelOS.SDK.Services
             {
                 return (msgid, -1);
             }
-
-            try
+            
+             try
             {
                 //1.再次检查投票
                 var client = _azureCosmos.GetCosmosClient();
@@ -69,12 +69,38 @@ namespace TEAMModelOS.SDK.Services
                 {
 
                     //判断投票时间是否在起止时间内
-                    if (curr >= vote.startTime && curr <= vote.endTime)
+
+                    string optfrom = "";
+                    ///操作来源,如果是研修的,不限制,否则现在活动结束后不能再投票或者提交问卷作答。
+                    if (request.TryGetProperty("optfrom", out JsonElement _optFrom))
+                    {
+                        optfrom = $"{_optFrom}";
+                    }
+                    // if (curr >= vote.startTime && curr <= vote.endTime)
+                    bool intime=true;//默认有效期内
+                    var endDtae = DateTimeOffset.FromUnixTimeMilliseconds(vote.endTime); 
+                    if (!string.IsNullOrWhiteSpace(optfrom) && optfrom.Equals("train"))
+                    { //"optfrom":"train"  代表是研修的
+                        if (curr >= vote.startTime)
+                        {
+                            intime = true;
+                          
+                        }
+                        else { intime = false; }
+                        endDtae = DateTimeOffset.UtcNow;
+                    }
+                    else {
+                        if (curr >= vote.startTime && curr <= vote.endTime)
+                        {
+                            intime = true;
+                            endDtae = DateTimeOffset.FromUnixTimeMilliseconds(vote.endTime);
+                        }
+                        else { intime = false; }
+                    }
+                    if (intime)
                     {
                         string endField = null;
-
                         string Field = "";
-                        var endDtae = DateTimeOffset.FromUnixTimeMilliseconds(vote.endTime);
                         RedisValue value;
                         switch (vote.times)
                         {
@@ -546,8 +572,37 @@ namespace TEAMModelOS.SDK.Services
                 }
                 if (survey != null)
                 {
+                    string optfrom = "";
+                    ///操作来源,如果是研修的,不限制,否则现在活动结束后不能再投票或者提交问卷作答。
+                    if (request.TryGetProperty("optfrom", out JsonElement _optFrom))
+                    {
+                        optfrom = $"{_optFrom}";
+                    }
+                    // if (curr >= vote.startTime && curr <= vote.endTime)
+                    bool intime = true;//默认有效期内
+                    var endDtae = DateTimeOffset.FromUnixTimeMilliseconds(survey.endTime);
+                    if (!string.IsNullOrWhiteSpace(optfrom) && optfrom.Equals("train"))
+                    { //"optfrom":"train"  代表是研修的
+                        if (curr >= survey.startTime)
+                        {
+                            intime = true;
+
+                        }
+                        else { intime = false; }
+                        endDtae = DateTimeOffset.UtcNow;
+                    }
+                    else
+                    {
+                        if (curr >= survey.startTime && curr <= survey.endTime)
+                        {
+                            intime = true;
+                            endDtae = DateTimeOffset.FromUnixTimeMilliseconds(survey.endTime);
+                        }
+                        else { intime = false; }
+                    }
                     //判断投票时间是否在起止时间内
-                    if (curr >= survey.startTime && curr <= survey.endTime)
+                    //    if (curr >= survey.startTime && curr <= survey.endTime)
+                    if (intime)
                     {
                         if (request.TryGetProperty("record", out JsonElement _record))
                         {

+ 1 - 0
TEAMModelOS/ClientApp/package.json

@@ -109,6 +109,7 @@
     "babel-plugin-component": "^1.1.1",
     "babel-plugin-import": "^1.12.0",
     "babel-polyfill": "^6.26.0",
+    "clean-webpack-plugin": "^4.0.0",
     "cross-env": "^5.2.1",
     "css-loader": "^4.2.1",
     "eslint": "^5.16.0",

+ 1 - 1
TEAMModelOS/ClientApp/public/lang/zh-CN.js

@@ -4128,7 +4128,7 @@ const LANG_ZH_CN = {
         idWarning: '警告:Excel 內账号重复!',
         idFormatWarning: '错误:学生账号格式为4-12位数字',
         gradeWarning: '警告:年级错误',
-        setNoErr: "错误:座位号已在校內重复",
+        setNoErr: "错误:座号与校内该班级已有学生重复",
         downloadText: '(下载名单模板)',
         idRepErr: '账号已存在,将覆盖原有账号',
         stuYearErr: '学生学级数据错误',

+ 1 - 1
TEAMModelOS/ClientApp/public/lang/zh-TW.js

@@ -4129,7 +4129,7 @@ const LANG_ZH_TW = {
         idWarning: '警告:Excel 內帳號重複! ',
         idFormatWarning: '錯誤:學生帳號格式為4-12位數字',
         gradeWarning: '警告:年級錯誤',
-        setNoErr: "錯誤:座號已在校內重複",
+        setNoErr: "錯誤:座號與校內該班級已有學生重復",
         downloadText: '(下載名單模板)',
         idRepErr: '帳號已存在,將覆蓋原有帳號',
         stuYearErr: '學生學級數據錯誤',

+ 4 - 0
TEAMModelOS/ClientApp/src/api/areaArt.js

@@ -42,5 +42,9 @@ export default {
     /* 获取艺术评测看板数据 */
     findArtDashAnalysis: function (data) {
         return post('/analysis/art/statistics', data)
+    },
+    /* 获取学区学校列表 */
+    findAreaSchoolList: function (data) {
+        return post('/school/area/find-school', data)
     }
 }

+ 4 - 4
TEAMModelOS/ClientApp/src/common/BaseLayout.vue

@@ -950,16 +950,16 @@ export default {
       }
       this.isShowLogo = cloudSetting.logoStatus === 'open'
     }
-    this.$EventBus.$off('onGlobalLoading')
-    this.$EventBus.$on('onGlobalLoading', val => {
-      this.getSystemLevel()
-    })
   },
   mounted() {
     this.$EventBus.$off('onLogoStatusChange')
     this.$EventBus.$on('onLogoStatusChange', val => {
       this.isShowLogo = val === 'open'
     })
+    this.$EventBus.$off('onGlobalLoading')
+    this.$EventBus.$on('onGlobalLoading', val => {
+      this.getSystemLevel()
+    })
     this.getSystemLevel()
   },
   watch: {

+ 33 - 8
TEAMModelOS/ClientApp/src/view/areaArtExam/DataView.vue

@@ -48,16 +48,16 @@
             </div>
         </div>
         <div class="table-header-wrap">
-            <Select v-model="schoolId" style="width: 200px;margin-right:10px" placeholder="学校">
+            <Select v-model="value" style="width: 200px;margin-right:10px" placeholder="学校" @on-change="onSchoolChange">
                 <Option v-for="item in schoolList" :value="item.id" :key="item.id">{{ item.name }}</Option>
             </Select>
-            <Select v-model="classId" style="width: 200px">
+            <Select v-model="classId" style="width: 200px" placeholder="班级">
                 <Option v-for="item in classList" :value="item.id" :key="item.id">{{ item.name }}</Option>
             </Select>
             <Input search v-model="keyword" placeholder="搜索学生..." style="margin-left:10px;width: 200px" @on-search="searchStudent" />
         </div>
         <div class="table-scroll-wrap">
-            <vuescroll>
+            <vuescroll v-if="artInfo.classes && artInfo.classes.length">
                 <Table :columns="columns" :data="tableDataShow" border>
                     <template slot-scope="{ row }" v-for="s in slotList" :slot="s">
                         <div :key="s" style="padding:5px 5px">
@@ -75,9 +75,10 @@
                     </template>
                 </Table>
             </vuescroll>
+            <TipsInfo v-else msg="学校尚未选择参与班级"></TipsInfo>
         </div>
         <!-- 分页 -->
-        <div class="page-wrap">
+        <div class="page-wrap" v-if="artInfo.classes && artInfo.classes.length">
             <Page show-total size="small" :current="currentPage" :total="tableData.length" :page-size="pageSize" @on-change="pageChange" />
         </div>
     </div>
@@ -107,7 +108,21 @@ export default {
             default: () => {
                 return []
             }
-        }
+        },
+        schoolList: {
+            type: Array,
+            default: () => {
+                return []
+            }
+        },
+        value: {
+            type: String,
+            default: ''
+        },
+    },
+    model: {
+        prop: "value", //绑定的值,通过父组件传递
+        event: "on-school-change", //自定义时间名    
     },
     computed: {
         curClass() {
@@ -159,8 +174,7 @@ export default {
     },
     data() {
         return {
-            schoolList:[],
-            schoolId:'',
+            // schoolId:'',
             keyword: '',
             pageSize: 10,
             currentPage: 1,
@@ -172,6 +186,9 @@ export default {
         }
     },
     methods: {
+        onSchoolChange(){
+            this.$emit('on-school-change',this.value)
+        },
         searchStudent() {
             this.tableData = this.oringinData.filter(item => item.name.includes(this.keyword))
             this.pageChange(1)
@@ -248,7 +265,15 @@ export default {
                     this.classId = ''
                 }
             }
-        }
+        },
+        // schoolList:{
+        //     immediate:true,
+        //     handler(n,o){
+        //         if(n && n.length && !this.schoolId){
+        //             this.schoolId = n[0].id
+        //         }
+        //     }
+        // }
     }
 }
 </script>

+ 59 - 33
TEAMModelOS/ClientApp/src/view/areaArtExam/Mgt.vue

@@ -34,27 +34,26 @@
                         评价指标
                     </span>
                 </div>
-                <DataView :artInfo="artInfo" :quotaFirstLevel="quotaFirstLevel" :classList="classList" v-if="curBarIndex === 0"></DataView>
+                <DataView v-model="schoolId" @on-school-change="handleSchoolChange(1)" :artInfo="artInfo" :quotaFirstLevel="quotaFirstLevel" :classList="classList" v-if="curBarIndex === 0" :schoolList="schoolList"></DataView>
                 <div v-else-if="curBarIndex === 1" class="quo-detail-wrap">
                     <vuescroll style="background:white">
                         <Tabs v-model="tabName" style="padding: 0px 10px;margin-top:15px">
                             <template slot="extra">
                                 <div class="art-filter-wrap">
-                                    <!-- <span>{{$t('ae.ae6')}}:</span> -->
-                                    <Select v-model="schoolId" style="width: 200px" placeholder="学校">
+                                    <Select v-model="schoolId" style="width: 200px;margin-right:10px" placeholder="学校" transfer @on-change="handleSchoolChange(2)">
                                         <Option v-for="item in schoolList" :value="item.id" :key="item.id">{{ item.name }}</Option>
                                     </Select>
-                                    <Select v-model="classId" style="width: 200px" placeholder="班级">
+                                    <Select v-model="classId" style="width: 200px;margin-right:10px" placeholder="班级">
                                         <Option v-for="item in classList" :value="item.id" :key="item.id">{{ item.name }}</Option>
                                     </Select>
-                                    <!-- <span style="margin-left:10px">{{$t('ae.ae4')}}:</span> -->
                                     <Select v-model="subjectId" style="width: 120px" placeholder="学科">
                                         <Option v-for="item in subjectList" :value="item.id" :key="item.id">{{ item.name }}</Option>
                                     </Select>
                                 </div>
                             </template>
                             <TabPane v-for="(item, index) in tabListShow" :key="index" :label="item.label" :name="item.name">
-                                <AcQuos :artInfo="artInfo" :treeData="tabTree[item.name]" :curClass="curClass" :subjectId="subjectId"></AcQuos>
+                                <AcQuos v-if="artInfo.classes && artInfo.classes.length" :artInfo="artInfo" :treeData="tabTree[item.name]" :curClass="curClass" :subjectId="subjectId"></AcQuos>
+                                <TipsInfo v-else msg="学校尚未选择参与班级"></TipsInfo>
                             </TabPane>
                         </Tabs>
                     </vuescroll>
@@ -73,6 +72,7 @@ export default {
     },
     data() {
         return {
+            hasPublish:true,
             schoolId:'',
             schoolList:[],
             tabName: '',
@@ -87,7 +87,7 @@ export default {
             classId: '',
             subjectId: '',
             curBarIndex: 0,
-            tabTree: {}
+            tabTree: {},
         }
     },
     computed: {
@@ -123,6 +123,22 @@ export default {
         }
     },
     methods: {
+        handleSchoolChange(value){
+            console.log(value)
+            this.findArtSummary()
+        },
+        getAreaSchoolList(){
+            this.$api.areaArt.findAreaSchoolList({
+                id:sessionStorage.getItem('areaId')
+            }).then(
+                res=>{
+                    this.schoolList = res.sc
+                },
+                err=>{
+                    this.$Message.error("获取学校列表失败")
+                }
+            )
+        },
         selectBar(tab) {
             this.curBarIndex = tab
         },
@@ -174,9 +190,9 @@ export default {
             this.classId = ''
             this.subjectId = ''
             this.curIndex = index
-            setTimeout(() => {
-                this.findArtSummary()
-            })
+            //TODO过滤学校
+            this.schoolId = this.schoolList[0] ?  this.schoolList[0].id : ''
+            this.findArtSummary()
         },
         toCreate() {
             this.$router.push({
@@ -191,33 +207,40 @@ export default {
             this.$api.areaArt.findAreaArtList(params).then(
                 (res) => {
                     this.artList = res.arts
-                    if (this.artList.length) this.findArtSummary()
+                    if (this.artList.length) this.selectArt(0)
                 },
                 (err) => { }
             )
         },
         findArtSummary() {
-            // this.classList = []
-            // let params = {
-            //     id: this.artList[this.curIndex].id,
-            //     code: this.$store.state.userInfo.schoolCode
-            // }
-            // this.$api.areaArt.findArtSummary(params).then(
-            //     (res) => {
-            //         this.artInfo = res.art
-            //         this.tabListShow = this.tabList.filter(item => {
-            //             return !!this.artInfo.settings.find(s => s.id.includes(item.name))
-            //         })
-            //         if (this.tabListShow.length) {
-            //             this.tabName = this.tabListShow[0].name
-            //         }
-            //         this.handleTabTree()
-            //         if (this.artInfo?.classes) {
-            //             this.getClassList()
-            //         }
-            //     },
-            //     (err) => { }
-            // )
+            if(!this.schoolId) return
+            let sArt = this.artList[this.curIndex].sc?.find(item=>item.code === this.schoolId)
+            if(!sArt) return
+            let sId = sArt.id
+            this.classList = []
+            let params = {
+                id: sId,
+                code: this.schoolId
+            }
+            this.$api.areaArt.findArtSummary(params).then(
+                (res) => {
+                    this.artInfo = res.art
+                    this.tabListShow = this.tabList.filter(item => {
+                        return !!this.artInfo.settings.find(s => s.id.includes(item.name))
+                    })
+                    if (this.tabListShow.length) {
+                        this.tabName = this.tabListShow[0].name
+                    }
+                    this.handleTabTree()
+                    this.classes = []
+                    if (this.artInfo?.classes?.length) {
+                        this.getClassList()
+                    }else{
+                        this.hasPublish = false
+                    }
+                },
+                (err) => { }
+            )
         },
         curSettings(tabName) {
             if (tabName && this.artInfo?.settings) {
@@ -257,7 +280,7 @@ export default {
         getClassList() {
             let req = {
                 ids: this.artInfo.classes,
-                schoolId: this.$store.state.userInfo.schoolCode
+                schoolId: this.schoolId
             }
             this.$api.common.getGroupListByIds(req).then(
                 res => {
@@ -270,6 +293,7 @@ export default {
         },
     },
     created() {
+        this.getAreaSchoolList()
         this.getAreaSetting()
     },
     watch: {
@@ -279,6 +303,8 @@ export default {
             handler(n, o) {
                 if (n && n.length) {
                     this.classId = n[0].id
+                }else{
+                    this.classId = ''
                 }
             }
         },

+ 1 - 1
TEAMModelOS/ClientApp/src/view/areaMgmt/AreaLayout.vue

@@ -461,7 +461,7 @@ export default {
       return res
     },
     isShowArtMenu() {
-      let schoolProfile = JSON.parse(decodeURIComponent(localStorage.school_profile, "utf-8"))
+      let schoolProfile = JSON.parse(decodeURIComponent(localStorage.school_profile || '{}', "utf-8"))
       let areaArt = schoolProfile.areaShows?.find(item => item.code == this.areaId && item.status === 1)
       return !!areaArt
     },

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

@@ -343,7 +343,8 @@ export default {
             return new Promise(async (r, j) => {
                 try {
                     simplePaper.scope = "school"
-                    let fullPaper = await this.$evTools.getFullPaper(simplePaper)
+                    simplePaper.code = "hbcn"
+                    let fullPaper = await this.$evTools.getStuPaper(simplePaper)
                     if (fullPaper) {
                         let apiPaper = {}
                         apiPaper.id = fullPaper.id

+ 2 - 0
TEAMModelOS/ClientApp/src/view/artexam/QuoTree.vue

@@ -9,6 +9,7 @@
 		:render-content="renderContent"
         @check="hanldeCheckChange"
 		:render-after-expand="false"
+		:default-checked-keys="['quota_21','quota_22']"
 	></el-tree>
 </template>
 
@@ -80,6 +81,7 @@ export default {
 									},
 									on: {
 										"on-set-exam": (data) => {
+											console.log(data)
 											_this.$set(_this.settingMap,node.data.id,data)
 										}
 									}

+ 10 - 3
TEAMModelOS/ClientApp/src/view/assessment/ArtAssessment.vue

@@ -21,7 +21,7 @@
           </Option>
         </Select>
         <!-- 搜索框 -->
-        <Input v-special-char v-model="searchVal" search :placeholder="$t('ability.place1')" style="width: 180px;margin-left: 15px;" @on-search="doFilter" />
+        <Input v-special-char v-model="searchVal" search :placeholder="$t('ability.place1')" style="width: 180px;margin-left: 15px;" @on-search="onSearch" />
       </div>
       <div class="right">
         <p>查询结果:共 <span>{{ totalCount }}</span> 人, 优秀 <span :style="{color:colorList[0]}">{{ levelCount[0] }}</span> 人, 良好 <span :style="{color:colorList[1]}">{{ levelCount[1] }}</span> 人, 合格 <span :style="{color:colorList[2]}">{{ levelCount[2] }}</span> 人, 不合格 <span :style="{color:colorList[3]}">{{ levelCount[3] }}</span> 人 </p>
@@ -183,7 +183,7 @@ export default {
   },
   data(vm) {
     return {
-      colorList: ['#23c466', '#c47c18', '#c49258', '#ff0000'],
+      colorList: ['#23c466', '#23c466', '#c47c18', '#c47c18', '#c49258', '#c49258', '#ff0000'],
       levelCount: [0, 0, 0, 0],
       totalCount: 0,
       previewModal: false,
@@ -525,6 +525,13 @@ export default {
       this.originList = []
       this.doFilter()
     },
+    /* 搜索名称 */
+    onSearch() {
+      this.continueToken = null
+      this.assessmentList = [];
+      this.originList = []
+      this.doFilter()
+    },
     /* 查询操作 */
     doFilter() {
       this.expandedArr = []
@@ -546,7 +553,7 @@ export default {
           this.originList = this._.cloneDeep(this.assessmentList)
           this.levelCount = new Array(this.artSettings.reviewLevel.length).fill(0)
           this.calcQuotaScores(stuResults)
-          this.calcFinalCounts(res.scores)
+          this.calcFinalCounts(res.subjectScore[0].name)
         } else {
           this.$Message.error('Fail')
         }

+ 2 - 1
TEAMModelOS/ClientApp/src/view/jyzx/offline.vue

@@ -413,7 +413,8 @@ export default {
                     "userid": this.$store.state.userInfo.TEAMModelId,
                     "code": this.surveyInfo.code,
                     "id": this.surveyInfo.id,
-                    record: this.myAnswer.map(i => Array.isArray(i) ? i : [i])
+                    record: this.myAnswer.map(i => Array.isArray(i) ? i : [i]),
+                    optfrom: "train"
                 }
                 this.$api.jyzx.answerSurvey(params).then(res => {
                     // msgid = 0投票失败,1 提交成功,2 不在时间范围内,3 不在发布范围内,6 未设置投票项

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

@@ -596,6 +596,7 @@ export default {
                                     this.stuList.splice(index, 1)
                                 }
                             })
+                            this.hanldeFilterExp()
                             this.selectList(0)
                             this.$Message.success(this.$t('teachermgmt.rmvOk'))
                         },
@@ -633,6 +634,7 @@ export default {
                     } else {
                         this.stuList.splice(this.curIndex, 1, params)
                     }
+                    this.hanldeFilterExp()
                     this.rmSelctions = []
                     this.$refs['studentList'].clearTable()
                 },

+ 2 - 1
TEAMModelOS/ClientApp/src/view/teachcontent/index.vue

@@ -1059,7 +1059,8 @@ export default {
     },
     openPreviewFile(index, row) {
       let activeType = this.activeType
-      if (!row || (['image', 'audio', 'doc'].includes(activeType) || (activeType == 'video' && row.extension == 'MP4') || (activeType == 'res' && row.extension == 'HTEX'))) {
+      // if (!row || (['image', 'audio', 'doc'].includes(activeType) || (activeType == 'video' && row.extension == 'MP4') || (activeType == 'res' && row.extension == 'HTEX'))) {
+      if (!row || (['image', 'audio', 'doc'].includes(activeType) || (activeType == 'video' && row.extension == 'MP4'))) {
         this.previewFile = this._.cloneDeep(this.fileListShow[index])
         if (this.activeType == 'image') {
           this.previewFile.url = this.previewFile.url.replace('thum/', '')

+ 16 - 11
TEAMModelOS/ClientApp/vue.config.js

@@ -1,4 +1,5 @@
 const path = require('path')
+const { CleanWebpackPlugin } = require('clean-webpack-plugin')
 const Timestamp = new Date().getTime();
 function resolve(dir) {
 	return path.join(__dirname, './', dir)
@@ -16,6 +17,7 @@ module.exports = {
 			entry: 'src/main.js',
 			template: 'public/index.html',
 			filename: 'index.html',
+			// chunks: ['chunk-vendors','chunk-common','app','chunk-viewDesign','chunk-static','chunk-konva','chunk-azure','chunk-xlsx','chunk-video','chunk-pdfjs','chunk-wangeditor','chunk-h2c','chunk-corejs']
 		}
 	},
 
@@ -53,8 +55,11 @@ module.exports = {
 			]
 		}
 	},
-
-
+	configureWebpack: {
+		plugins: [
+			new CleanWebpackPlugin()
+		]
+	},
 	configureWebpack: config => {
 		config.optimization.minimizer[0].options.terserOptions.compress.drop_console = process.env.NODE_ENV === 'production'
 		config.output.filename = `js/[name].${Timestamp}.js`
@@ -86,21 +91,21 @@ module.exports = {
 		// 			test: /[\\/]node_modules[\\/]/,
 		// 			priority: -10,
 		// 			chunks: 'all',
-		// 			enforce:true
+		// 			enforce: true
 		// 		},
 		// 		viewDesign: {
 		// 			name: "chunk-viewDesign",
 		// 			test: /[\\/]view-design[\\/]/,
 		// 			priority: 20, // 权重要大于 libs
 		// 			chunks: 'initial',
-		// 			enforce:true
+		// 			enforce: true
 		// 		},
 		// 		static: { // viewDesign 单独拆包
 		// 			name: "chunk-static",
 		// 			test: /[\\/]static[\\/]/,
 		// 			priority: 20, // 权重要大于 libs
 		// 			chunks: 'initial',
-		// 			enforce:true
+		// 			enforce: true
 		// 		},
 		// 		konva: { // viewDesign 单独拆包
 		// 			name: "chunk-konva",
@@ -108,7 +113,7 @@ module.exports = {
 		// 			priority: 30, // 权重要大于 libs
 		// 			chunks: 'all',
 		// 		},
-		// 		azure: { 
+		// 		azure: {
 		// 			name: "chunk-azure",
 		// 			test: /[\\/]@azure[\\/]/,
 		// 			priority: 20, // 权重要大于 libs
@@ -125,35 +130,35 @@ module.exports = {
 		// 			test: /[\\/]video.js[\\/]/,
 		// 			priority: 20,
 		// 			chunks: 'all',
-		// 			enforce:true
+		// 			enforce: true
 		// 		},
 		// 		pdfjs: {
 		// 			name: `chunk-pdfjs`,
 		// 			test: /[\\/]pdfjs-dist[\\/]/,
 		// 			priority: 20,
 		// 			chunks: 'all',
-		// 			enforce:true
+		// 			enforce: true
 		// 		},
 		// 		wangeditor: {
 		// 			name: `chunk-wangeditor`,
 		// 			test: /[\\/]wangeditor[\\/]/,
 		// 			priority: 20,
 		// 			chunks: 'all',
-		// 			enforce:true
+		// 			enforce: true
 		// 		},
 		// 		h2c: {
 		// 			name: `chunk-h2c`,
 		// 			test: /[\\/]html2canvas[\\/]/,
 		// 			priority: 20,
 		// 			chunks: 'all',
-		// 			enforce:true
+		// 			enforce: true
 		// 		},
 		// 		corejs: {
 		// 			name: `chunk-corejs`,
 		// 			test: /[\\/]core-js[\\/]/,
 		// 			priority: 20,
 		// 			chunks: 'all',
-		// 			enforce:true
+		// 			enforce: true
 		// 		}
 		// 	},
 		// }

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

@@ -629,9 +629,9 @@ namespace TEAMModelOS.Controllers
                 {
                     x.id,
                     x.name,
-                    x.stime,
-                    x.etime,
-                    sc = artSc.Where(c => c.pd.Equals(x.id)).Select(p => new { p.id, p.code })
+                    startTime = x.stime,
+                    endTime = x.etime,
+                    sc = artSc.Where(c => c.pd.Equals(x.id)).Select(p => new {p.id,p.code })
                 });
                 return Ok(new { arts });
             }

+ 2 - 2
TEAMModelOS/Controllers/OpenApi/OpenApiService.cs

@@ -838,10 +838,10 @@ namespace TEAMModelOS.Controllers
                 string insql = "";
                 if (coreUsers.Any())
                 {
-                    insql = $"   c.id in  ({string.Join(",", coreUsers.Select(x => $"'{x.id}'"))}) ";
+                    insql = $" where  c.id in  ({string.Join(",", coreUsers.Select(x => $"'{x.id}'"))}) ";
                 }
 
-                string sql = $"select c.id,c.name ,c.picture,c.job ,c.subjectIds,c.roles from c where   {insql}";
+                string sql = $"select c.id,c.name ,c.picture,c.job ,c.subjectIds,c.roles from c  {insql}";
                 await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<SchoolTeacher>
                     (queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Teacher-{school}") }))
                 {

+ 481 - 0
TEAMModelOS/Controllers/XTest/FixDataController.cs

@@ -31,6 +31,13 @@ using TEAMModelOS.Models;
 using System.Text.RegularExpressions;
 using TEAMModelOS.SDK.Services;
 using Azure.Messaging.ServiceBus;
+using TEAMModelOS.SDK.Models.Cosmos.BI;
+using static ICSharpCode.SharpZipLib.Zip.ZipEntryFactory;
+using Azure.Storage.Sas;
+using DocumentFormat.OpenXml.Drawing.Diagrams;
+using TEAMModelOS.SDK.Models.Dtos;
+using DocumentFormat.OpenXml.Bibliography;
+using System.Formats.Asn1;
 
 namespace TEAMModelOS.Controllers
 {
@@ -2966,5 +2973,479 @@ namespace TEAMModelOS.Controllers
                 return BadRequest(ex.StackTrace);
             }
         }
+
+        /// <summary>
+        /// 修复研修平台账号重复的问题
+        /// </summary>
+        /// <param name="jsonElement"></param>
+        /// <returns></returns>
+        [HttpPost("fix-training")]
+        public async Task<IActionResult> RepairTraining(JsonElement jsonElement) 
+        {
+            try
+            {
+                if (!jsonElement.TryGetProperty("trainingIds", out JsonElement ids)) return BadRequest();
+                List<TrainingId> trainingIds = ids.ToObject<List<TrainingId>>();
+                List<string> noCopyFiles = new();
+
+                var table = _azureStorage.GetCloudTableClient().GetTableReference("ScYxpt");
+                var cosmosClient = _azureCosmos.GetCosmosClient();
+
+                foreach (var item in trainingIds)
+                {
+                    List<ScTeacher> scTeachers = await table.FindListByDict<ScTeacher>(new Dictionary<string, object>() { { "PartitionKey", "ScTeacher" }, { "tmdid", $"{item.oldId}" } });
+                    if (scTeachers.Count > 0)
+                    {
+                        scTeachers.ForEach(sct => sct.tmdid = item.newId);
+                        //保存和更新研修信息
+                        await table.SaveOrUpdateAll(scTeachers);
+                    }
+                    string defaultSc = null;
+
+                    //教师基础信息
+                    Teacher teacher = new();
+                    var resTchBase = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync($"{item.oldId}", new PartitionKey("Base"));
+                    if (resTchBase.Status == 200)
+                    {
+                        using var json = await JsonDocument.ParseAsync(resTchBase.ContentStream);
+                        teacher = json.ToObject<Teacher>();
+                        defaultSc = teacher.defaultSchool;
+                        if (string.IsNullOrEmpty(teacher.defaultSchool))
+                            defaultSc = teacher.schools[0].schoolId;
+
+                        teacher.id = $"{item.newId}";
+                        //教师基础信息
+                        teacher = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<Teacher>(teacher, new PartitionKey(teacher.code));
+                    }
+
+                    //教师研修文件
+                    TeacherFile teacherFile = new();
+                    var resTchFile = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync($"{item.oldId}", new PartitionKey($"TeacherFile-{defaultSc}"));
+                    if (resTchFile.Status == 200)
+                    {
+                        using var json = await JsonDocument.ParseAsync(resTchFile.ContentStream);
+                        teacherFile = json.ToObject<TeacherFile>();
+                        teacherFile.id = $"{item.newId}";
+                        //创建新的教师研修文件
+                        teacherFile = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<TeacherFile>(teacherFile, new PartitionKey(teacherFile.code));
+                    }
+
+                    //研修统计
+                    TeacherTrain teacherTrain = new();
+                    var resTchTrain = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync($"{item.oldId}", new PartitionKey($"TeacherTrain-{defaultSc}"));
+                    if (resTchTrain.Status == 200)
+                    {
+                        using var json = await JsonDocument.ParseAsync(resTchTrain.ContentStream);
+                        teacherTrain = json.ToObject<TeacherTrain>();
+                        teacherTrain.tmdid = $"{item.newId}";
+                        teacherTrain.id = $"{item.newId}";
+                        //研修报告外层文件路径
+                        if (!string.IsNullOrEmpty($"{teacherTrain.offlineUrl}"))
+                        {
+                            string oldOffUrl = teacherTrain.offlineUrl;
+                            teacherTrain.offlineUrl = teacherTrain.offlineUrl.Replace($"/{item.oldId}/", $"/{item.newId}/");
+                            if (!oldOffUrl.Equals(teacherTrain.offlineUrl))
+                            {
+                                //复制研修报告
+                                var tempFileCopy = await BatchCopyFileService.SingleCopyFile(_azureStorage, "teammodelos", teacherTrain.offlineUrl, item.oldId, item.newId);
+                                if (tempFileCopy != 200)
+                                    noCopyFiles.Add(oldOffUrl);
+                            }
+                        }
+
+                        if (teacherTrain.offlineRecords.Count > 0)
+                        {
+                            foreach (var off in teacherTrain.offlineRecords)
+                            {
+                                if (!string.IsNullOrEmpty(off.url))
+                                {
+                                    string oldOffRe = off.url;
+                                    off.url = off.url.Replace($"/{item.oldId}/", $"/{item.newId}/");
+                                    if (!oldOffRe.Equals(off.url))
+                                    {
+                                        //线下研修文件
+                                        var tempFileRe = await BatchCopyFileService.SingleCopyFile(_azureStorage, defaultSc, oldOffRe, item.oldId, item.newId);
+                                        if (tempFileRe != 200)
+                                            noCopyFiles.Add(oldOffRe);
+                                    }
+                                }
+                                if (off.other != null)
+                                {
+                                    //作业附件
+                                    foreach (var offOther in off.other)
+                                    {
+                                        //替换文件路径
+                                        string oldOffOther = offOther.url;
+                                        offOther.url = offOther.url.Replace($"/{item.oldId}/", $"/{item.newId}/");
+                                        offOther.blob = offOther.blob.Replace($"/{item.oldId}/", $"/{item.newId}/");
+                                        if (!oldOffOther.Equals(offOther.url))
+                                        {
+                                            //复制作业附件
+                                            var tempFileCopy = await BatchCopyFileService.SingleCopyFile(_azureStorage, defaultSc, oldOffOther, item.oldId, item.newId);
+                                            if (tempFileCopy != 200)
+                                                noCopyFiles.Add(oldOffOther);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        if (teacherTrain.teacherClasses.Count > 0)
+                        {
+                            //课堂实录
+                            foreach (var tchClass in teacherTrain.teacherClasses)
+                            {
+                                string tchCla = tchClass.url;
+                                //替换课堂实录路径地址
+                                tchClass.url = tchClass.url.Replace($"/{item.oldId}/", $"/{item.newId}/");
+                                if (!tchCla.Equals(tchClass.url))
+                                {
+                                    //复制课堂实录文件
+                                    var tempFileCopy = await BatchCopyFileService.SingleCopyFile(_azureStorage, defaultSc, tchCla, item.oldId, item.newId);
+                                    if (tempFileCopy != 200)
+                                        noCopyFiles.Add(tchCla);
+                                }
+                            }
+                        }
+
+                        //研修报告信息
+                        if (teacherTrain.offlineReport != null)
+                        {
+                            //替换研修报告信息文件路径地址
+                            string tchTrain = teacherTrain.offlineReport.url;
+                            teacherTrain.offlineReport.url = teacherTrain.offlineReport.url.Replace($"/{item.oldId}/", $"/{item.newId}/");
+                            teacherTrain.offlineReport.blob = teacherTrain.offlineReport.blob.Replace($"/{item.oldId}/", $"/{item.newId}/");
+                            if (!tchTrain.Equals(teacherTrain.offlineReport.url))
+                            {
+                                //研修报告信息文件路径
+                                var tempFileCopy = await BatchCopyFileService.SingleCopyFile(_azureStorage, "teammodelos", tchTrain, item.oldId, item.newId);
+                                if (tempFileCopy != 200)
+                                    noCopyFiles.Add(tchTrain);
+                            }
+                        }
+                        teacherTrain.id = item.newId;
+                        //创建新的教师研修统计
+                        teacherTrain = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<TeacherTrain>(teacherTrain, new PartitionKey(teacherTrain.code));
+                    }
+
+                    //课堂实录
+                    ClassVideo classVideo = new();
+                    var respCalsVideo = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync($"{item.oldId}", new PartitionKey($"ClassVideo-{defaultSc}"));
+                    if (respCalsVideo.Status == 200)
+                    {
+                        using var json = await JsonDocument.ParseAsync(respCalsVideo.ContentStream);
+                        classVideo = json.ToObject<ClassVideo>();
+                        classVideo.creatorId = $"{item.newId}";
+                        if (classVideo.files.Count > 0)
+                        {
+                            foreach (var cv in classVideo.files)
+                            {
+                                string tchCla = cv.url;
+                                cv.url = cv.url.Replace($"/{item.oldId}/", $"/{item.newId}/");
+                                if (!tchCla.Equals(cv.url))
+                                {
+                                    //复制课堂实录文件
+                                    var tempFileCopy = await BatchCopyFileService.SingleCopyFile(_azureStorage, defaultSc, tchCla, item.oldId, item.newId);
+                                    if (tempFileCopy != 200)
+                                        noCopyFiles.Add(tchCla);
+                                }
+                            }
+                        }
+
+                        classVideo.id = $"{item.newId}";
+                        //创建新的教师课堂实录
+                        classVideo = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<ClassVideo>(classVideo, new PartitionKey(classVideo.code));
+                    }
+
+                    //订阅记录和学习记录
+                    List<Task<ItemResponse<AbilitySub>>> abilitySubs = new();
+                    await foreach (var abilitySub in cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<AbilitySub>(queryText: "select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"AbilitySub-{defaultSc}-{item.oldId}") }))
+                    {
+                        abilitySub.creatorId = item.newId;
+                        if (abilitySub.uploads.Count > 0)
+                        {
+                            foreach (var asup in abilitySub.uploads)
+                            {
+                                if (asup.urls.Count > 0)
+                                {
+                                    foreach (var asupurl in asup.urls)
+                                    {
+                                        string asupUr = asupurl.url;
+                                        asupurl.url = asupurl.url.Replace($"/{item.oldId}/", $"/{item.newId}/");
+                                        if (!asupUr.Equals(asupurl.url))
+                                        {
+                                            //订阅记录和学习记录文件地址
+                                            var tempFileCopy = await BatchCopyFileService.SingleCopyFile(_azureStorage, defaultSc, asupUr, item.oldId, item.newId);
+                                            if (tempFileCopy != 200)
+                                                noCopyFiles.Add(asupUr);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+
+                        if (abilitySub.otherScore.Count > 0)
+                        {
+                            foreach (var abother in abilitySub.otherScore)
+                            {
+                                if (abother.tmdid.Equals(item.oldId))
+                                    abother.tmdid = item.oldId;
+                            }
+                        }
+
+                        abilitySub.code = abilitySub.code.Replace($"-{item.oldId}", $"-{item.newId}");
+                        abilitySubs.Add(cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<AbilitySub>(abilitySub, new PartitionKey($"AbilitySub-{defaultSc}-{item.newId}")));
+                    }
+
+                    if (abilitySubs.Count < 256)
+                        await Task.WhenAll(abilitySubs);
+                    else
+                    {
+                        int pages = (abilitySubs.Count + 255) / 256;
+                        for (int i = 0; i < pages; i++)
+                        {
+                            List<Task<ItemResponse<AbilitySub>>> tempAbilSub = abilitySubs.Skip((i) * 256).Take(256).ToList();
+                            await Task.WhenAll(tempAbilSub);
+                        }
+                    }
+
+                    //教师所在学校的基础信息
+                    SchoolTeacher schoolTeacher = new();
+                    var resScTeacher = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{item.oldId}", new PartitionKey($"Teacher-{defaultSc}"));
+                    if (resScTeacher.Status == 200)
+                    {
+                        using var json = await JsonDocument.ParseAsync(resScTeacher.ContentStream);
+                        schoolTeacher = json.ToObject<SchoolTeacher>();
+                        schoolTeacher.id = item.newId;
+
+                        //创建新的教师在学校的基础信息
+                        schoolTeacher = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync<SchoolTeacher>(schoolTeacher, new PartitionKey(schoolTeacher.code));
+                    }
+
+                    //名单信息
+                    List<Task<ItemResponse<GroupList>>> groupLists = new();
+                    await foreach (var grups in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<GroupList>(queryText: "select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"GroupList-{defaultSc}") }))
+                    {
+                        bool isReplace = false;
+                        if (grups.members.Count > 0)
+                        {
+                            foreach (var griupm in grups.members)
+                            {
+                                if (griupm.id.Equals(item.oldId))
+                                {
+                                    griupm.id = item.newId;
+                                    isReplace = true;
+                                }
+                            }
+                        }
+                        if (grups.creatorId.Equals(item.oldId))
+                        {
+                            grups.creatorId = item.newId;
+                            isReplace = true;
+                        }
+
+                        if (isReplace == true)
+                            groupLists.Add(cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<GroupList>(grups, grups.id, new PartitionKey(grups.code)));
+                    }
+
+                    if (groupLists.Count < 256)
+                        await Task.WhenAll(groupLists);
+                    else
+                    {
+                        int pages = (groupLists.Count + 255) / 256;
+                        for (int i = 0; i < pages; i++)
+                        {
+                            List<Task<ItemResponse<GroupList>>> tempGroups = groupLists.Skip((i) * 256).Take(256).ToList();
+                            await Task.WhenAll(tempGroups);
+                        }
+                    }
+
+                    //教研活动
+                    List<Task<ItemResponse<Study>>> studys = new();
+                    await foreach (var study in cosmosClient.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<Study>(queryText: "select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Study-{defaultSc}") }))
+                    {
+                        bool isReplace = false;
+                        if (study.creatorId.Equals(item.oldId))
+                        {
+                            study.creatorId = item.newId;
+                            isReplace = true;
+                        }
+                        if (study.teacIds.Contains(item.oldId) == true)
+                        {
+                            study.teacIds = study.teacIds.Select(x => x.Replace($"{item.oldId}", $"{item.newId}")).ToList();
+                            isReplace = true;
+                        }
+                        //if (isReplace == true)
+                        studys.Add(cosmosClient.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync<Study>(study, study.id, new PartitionKey($"Study-{defaultSc}")));
+                    }
+
+                    if (studys.Count < 256)
+                        await Task.WhenAll(studys);
+                    else
+                    {
+                        int pages = (studys.Count + 255) / 256;
+                        for (int i = 0; i < pages; i++)
+                        {
+                            List<Task<ItemResponse<Study>>> tempStudys = studys.Skip((i) * 256).Take(256).ToList();
+                            await Task.WhenAll(tempStudys);
+                        }
+                    }
+
+                    //教研测验活动记录
+                    List<Task<ItemResponse<ExamLite>>> examLites = new();
+                    await foreach (var examl in cosmosClient.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamLite>(queryText: $"select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamLite-{defaultSc}") }))
+                    {
+                        bool isReplace = false;
+                        if (examl.teachers.Count > 0)
+                        {
+                            foreach (var examTch in examl.teachers)
+                            {
+                                if (examTch.id.Equals(item.oldId))
+                                {
+                                    examTch.id = item.newId;
+                                    isReplace = true;
+                                }
+                            }
+                        }
+                        //if (isReplace == true)
+                        examLites.Add(cosmosClient.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync<ExamLite>(examl, examl.id, new PartitionKey($"ExamLite-{defaultSc}")));
+                    }
+
+                    if (examLites.Count < 256)
+                        await Task.WhenAll(examLites);
+                    else
+                    {
+                        int pages = (examLites.Count + 255) / 256;
+                        for (int i = 0; i < pages; i++)
+                        {
+                            List<Task<ItemResponse<ExamLite>>> tempExam = examLites.Skip((i) * 256).Take(256).ToList();
+                            await Task.WhenAll(tempExam);
+                        }
+                    }
+
+                    //作业记录
+                    List<Task<ItemResponse<HomeworkRecord>>> homeworkRecord = new();
+                    await foreach (var homerec in cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<HomeworkRecord>(queryText: $"select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"HomeworkRecord-{item.oldId}") }))
+                    {
+                        bool isReplace = false;
+                        if (homerec.content.Count > 0)
+                        {
+                            foreach (var hrCon in homerec.content)
+                            {
+                                if (hrCon.url.Contains($"/{item.oldId}/"))
+                                {
+                                    string hrUrl = hrCon.url;
+                                    hrCon.url = hrCon.url.Replace($"/{item.oldId}/", $"/{item.newId}/");
+                                    hrCon.blob = hrCon.blob.Replace($"/{item.oldId}/", $"/{item.newId}/");
+                                    //作业附件地址
+                                    var tempFileCopy = await BatchCopyFileService.SingleCopyFile(_azureStorage, defaultSc, hrUrl, item.oldId, item.newId);
+                                    if (tempFileCopy != 200)
+                                        noCopyFiles.Add(hrUrl);
+                                    isReplace = true;
+                                }
+                            }
+                        }
+
+                        if (isReplace == true)
+                        {
+                            homerec.code = homerec.code.Replace($"-{item.oldId}", $"-{item.newId}");
+                            homeworkRecord.Add(cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<HomeworkRecord>(homerec, new PartitionKey(homerec.code)));
+                        }
+                    }
+
+                    if (homeworkRecord.Count < 256)
+                        await Task.WhenAll(homeworkRecord);
+                    else
+                    {
+                        int pages = (homeworkRecord.Count + 255) / 256;
+                        for (int i = 0; i < pages; i++)
+                        {
+                            List<Task<ItemResponse<HomeworkRecord>>> tempHomeR = homeworkRecord.Skip((i) * 256).Take(256).ToList();
+                            await Task.WhenAll(tempHomeR);
+                        }
+                    }
+
+                    //视频点评
+                    List<Task<ItemResponse<Appraise>>> appraises = new();
+                    await foreach (var appra in cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<Appraise>(queryText: "select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Appraise-{item.oldId}") }))
+                    {
+                        bool isRepCode = false;
+                        bool isReplace = false;
+                        if (appra.code.Contains(item.oldId))
+                        {
+                            appra.code = appra.code.Replace($"-{item.oldId}", $"-{item.newId}");
+                            isRepCode = true;
+                        }
+                        if (appra.roles.Count > 0)
+                        {
+                            foreach (var appRoles in appra.roles)
+                            {
+                                if (appRoles.commentTmdid.Equals(item.oldId))
+                                {
+                                    appRoles.commentTmdid = item.newId;
+                                    isReplace = true;
+                                }
+                            }
+                        }
+
+                        if ((isRepCode == true && isReplace == true) || (isRepCode == true && isReplace == false))
+                            appraises.Add(cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<Appraise>(appra, new PartitionKey(appra.code)));
+                        if (isReplace == true && isRepCode == false)
+                            appraises.Add(cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Appraise>(appra, appra.id, new PartitionKey(appra.code)));
+                    }
+
+                    if (appraises.Count < 256)
+                        await Task.WhenAll(appraises);
+                    else
+                    {
+                        int pages = (appraises.Count + 255) / 256;
+                        for (int i = 0; i < pages; i++)
+                        {
+                            List<Task<ItemResponse<Appraise>>> tempAppra = appraises.Skip((i) * 256).Take(256).ToList();
+                            await Task.WhenAll(tempAppra);
+                        }
+                    }
+
+                    //话题记录
+                    List<Task<ItemResponse<Debate>>> debates = new();
+                    await foreach (var debate in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<Debate>(queryText: "select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Debate-{defaultSc}") }))
+                    {
+                        bool isReplace = false;
+                        if (debate.tmdid.Equals(item.oldId)) 
+                        {
+                            debate.tmdid = item.newId;
+                            isReplace = true;
+                        }
+
+                        if (debate.replies.Count > 0)
+                        {
+                            foreach (var deRep in debate.replies)
+                            {
+                                if (deRep.tmdid.Equals(item.oldId))
+                                {
+                                    deRep.tmdid = item.newId;
+                                    isReplace = true;
+                                }
+                            }
+                        }
+                        if (isReplace == true)
+                            await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<Debate>(debate, debate.id, new PartitionKey(debate.code));
+                    }
+                }
+
+                return Ok(new { state = 200, noCopyFiles });
+            }
+            catch (Exception ex)
+            {
+                return Ok(new { state = 500 });
+
+            }
+        }
+
+        public record TrainingId 
+        {
+            public string oldId { get; set; }
+
+            public string newId { get; set; }
+        }
     }
 }

+ 1 - 1
TEAMModelOS/TEAMModelOS.csproj

@@ -105,7 +105,7 @@
 
     <!-- Include the newly-built files in the publish output -->
     <ItemGroup>
-      <DistFiles Include="$(SpaRoot)dist\**" />
+      <DistFiles Include="$wwwroot\**" />
       <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
         <RelativePath>%(DistFiles.Identity)</RelativePath>
         <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>