Преглед на файлове

Merge branch 'develop' into ZJ/develop-20220831

zj преди 2 години
родител
ревизия
53b5850d15
променени са 49 файла, в които са добавени 1321 реда и са изтрити 613 реда
  1. 6 0
      TEAMModelBI/ClientApp/src/api/index.js
  2. 14 14
      TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue
  3. 72 15
      TEAMModelBI/ClientApp/src/view/areamanage/statistics.vue
  4. 122 38
      TEAMModelBI/ClientApp/src/view/created/created.vue
  5. 21 9
      TEAMModelBI/Controllers/BINormal/AreaRelevantController.cs
  6. 14 1
      TEAMModelBI/Controllers/BISchool/BatchSchoolController.cs
  7. 9 8
      TEAMModelBI/Controllers/Census/ActivitySticsController.cs
  8. 10 1
      TEAMModelBI/Controllers/Census/BlobLogController.cs
  9. 16 6
      TEAMModelBI/Controllers/Census/LessonSticsController.cs
  10. 12 51
      TEAMModelBI/Controllers/Census/SchoolController.cs
  11. 19 17
      TEAMModelBI/Lang/en-us.json
  12. 17 15
      TEAMModelBI/Lang/zh-cn.json
  13. 19 17
      TEAMModelBI/Lang/zh-tw.json
  14. 19 17
      TEAMModelOS.FunctionV4/Lang/en-us.json
  15. 17 15
      TEAMModelOS.FunctionV4/Lang/zh-cn.json
  16. 19 17
      TEAMModelOS.FunctionV4/Lang/zh-tw.json
  17. 5 3
      TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs
  18. 5 0
      TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj
  19. 4 4
      TEAMModelOS.SDK/Context/Constant/Constant.cs
  20. 16 2
      TEAMModelOS.SDK/DI/CoreAPI/CoreAPIHttpService.cs
  21. 3 2
      TEAMModelOS.SDK/Models/Service/LessonService.cs
  22. 4 4
      TEAMModelOS/ClientApp/public/lang/en-US.js
  23. 2 2
      TEAMModelOS/ClientApp/public/lang/zh-TW.js
  24. 10 10
      TEAMModelOS/ClientApp/src/api/service.js
  25. 52 12
      TEAMModelOS/ClientApp/src/common/BaseNotification.vue
  26. 31 3
      TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/Exam.vue
  27. 27 3
      TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/ExamQu.vue
  28. 171 0
      TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/PopQues.vue
  29. 32 0
      TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/RecordView.less
  30. 24 6
      TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/RecordView.vue
  31. 4 4
      TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/ScoreBarChart.vue
  32. 25 4
      TEAMModelOS/ClientApp/src/utils/public.js
  33. 16 5
      TEAMModelOS/ClientApp/src/view/Home.vue
  34. 236 219
      TEAMModelOS/ClientApp/src/view/areaMgmt/AreaBase.vue
  35. 91 2
      TEAMModelOS/ClientApp/src/view/art/AreaArtSetting.vue
  36. 3 4
      TEAMModelOS/Controllers/Both/GroupListController.cs
  37. 10 6
      TEAMModelOS/Controllers/Both/ShareController.cs
  38. 34 4
      TEAMModelOS/Controllers/Both/VolumeController.cs
  39. 2 1
      TEAMModelOS/Controllers/Client/HiTAControlller.cs
  40. 3 2
      TEAMModelOS/Controllers/Common/ExamController.cs
  41. 16 3
      TEAMModelOS/Controllers/Common/HomeworkController.cs
  42. 2 1
      TEAMModelOS/Controllers/School/CorrectController.cs
  43. 4 2
      TEAMModelOS/Controllers/School/SchoolController.cs
  44. 17 4
      TEAMModelOS/Controllers/School/SchoolTeacherController.cs
  45. 3 2
      TEAMModelOS/Controllers/Teacher/InitController.cs
  46. 19 17
      TEAMModelOS/Lang/en-us.json
  47. 17 15
      TEAMModelOS/Lang/zh-cn.json
  48. 19 17
      TEAMModelOS/Lang/zh-tw.json
  49. 8 9
      TEAMModelOS/appsettings.Development.json

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

@@ -69,6 +69,12 @@ export default {
     createdSchools(data) {
         return post('/batchschool/batch-school', data)
     },
+    //批量创校的数据验证
+    verifyContent(data){
+        return post('/batchschool/get-checlkexist',data)
+    },
+
+
     //区域管理和微能力点管理
     //切换为能力点 ***    Headers[x-auth-authtoken]
     changeCutstandard(data) {

+ 14 - 14
TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue

@@ -314,7 +314,7 @@
                   <p class="admin-List-title">
                     <div>当前管理学校列表</div>
                     <div><el-button size="small" type="primary" @click="adminOrsearch='search',adminIndex=-1" :icon="Search">
-                      <el-icon><Back /></el-icon>
+                      <!-- <el-icon><Back /></el-icon> -->
                       添加管理员</el-button></div>
                     </p>
                   <div class="examine-tables">
@@ -442,7 +442,7 @@
         </template>
       </el-dialog>
       <!--询问加入管理员方式-->
-      <el-dialog v-model="stageShow.state" :width="stageShow.width" :show-close="false"  :close-on-press-escape="false" :close-on-click-modal="false">
+      <el-dialog v-model="stageShow.state" :width="stageShow.width" :show-close="false"  :close-on-press-escape="false" :close-on-click-modal="false" before-close="stageShow.state=false">
         <div class="stagebox" v-if="stageShow.definedShow===false" v-loading="adminSchoold.allLoading" element-loading-text="正在设置相应内容...">
           <div class="stagebox-title">加入学区管理员</div>
           <div class="stagebox-text">请问加入学区管理员方式:</div>
@@ -450,13 +450,13 @@
             <div><el-button size="small" @click="addAreaadmin()">仅加入学区管理员</el-button></div>
             <div><el-button size="small" @click="batchAddadmin('all')">加入学区及成为所有学校管理员</el-button></div>
             <div><el-button size="small" @click="defined()">加入学区及自定义学校管理员</el-button></div>
-            <div><el-button size="small" @click="stageShow.state=false">取消</el-button></div>
+            <div><el-button size="small" @click="stageShow.state=false,stageShow.definedShow=false">取消</el-button></div>
           </div>
         </div>
         <div class="stagebox-defined" v-else-if="stageShow.definedShow ===true" v-loading="adminSchoold.customLoading" element-loading-text="正在设置相应内容...">
           <div class="stagebox-defined-title">
             <div class="left-title">学区学校列表</div>
-            <div class="right-back"><el-button size="small" type="primary" @click="stageShow.definedShow=false,stageShow.width='20%'"> <el-icon><Back /></el-icon>返回</el-button></div>
+            <div class="right-back"><el-button size="small" type="primary" @click="stageShow.definedShow=false,stageShow.width='20%'">返回</el-button></div>
           </div>
           <div class="stagebox-table">
             <el-table :data="stageShow.definedData" style="width: 100%" max-height="50vh" height="40vh" @selection-change="selectChange" empty-text="暂无数据">
@@ -499,7 +499,7 @@ import { useRouter } from 'vue-router'
 import Ability from '@/components/Ability.vue'
 import option from '@/static/region.json'
 import loadingsz from '@/components/loading/partial.vue'
-import { CopyDocument,Back } from '@element-plus/icons-vue'
+import { CopyDocument } from '@element-plus/icons-vue'
 import useClipboard from 'vue-clipboard3'
 const optionsData = option
 export default {
@@ -507,7 +507,6 @@ export default {
     Ability,
     loadingsz,
     CopyDocument,
-    Back
   },
   setup () {
     let { proxy } = getCurrentInstance()
@@ -583,6 +582,7 @@ export default {
     let adminIndex=ref(-1)
     let adminSchoold=ref({
       data:[],
+      original:[],
       loading:false,
       allLoading:false,
       customLoading:false,
@@ -637,7 +637,7 @@ export default {
       let data = { areaId: currentlySelect.value.id }
       proxy.$api.getForareaSchool(data).then((res) => {
         console.log(res, '现在区域拥有的学校')
-        res.state === 200 ? (tableDatas.value.push(...res.joinAreaSchools),stageShow.value.definedData.push(...res.joinAreaSchools),stageShow.value.original.push(...res.joinAreaSchools)) : ''
+        res.state === 200 ? (tableDatas.value.push(...res.joinAreaSchools),stageShow.value.definedData=res.joinAreaSchools,stageShow.value.original=res.joinAreaSchools) : ''
       })
     }
     //获取当前未加入区的所有学校
@@ -907,7 +907,7 @@ export default {
         .areaAddadmins(data)
         .then((res) => {
           console.log(res, '添加学区管理员返回')
-          res.state === 200 ? (ElMessage.success('操作成功'), stageShow.value.state=false,getAreasadmin()) : ''
+          res.state === 200 ? (ElMessage.success('操作成功'), stageShow.value.state=false,stageShow.value.definedShow=false,getAreasadmin()) : res.state === 201  && res.existsArea ?  ElMessage.warning('已是学区管理员,请勿重复添加'):''
         })
         .catch((error) => {
           ElMessage.error('添加学区管理员失败')
@@ -1014,12 +1014,12 @@ export default {
       timer.value = setTimeout(fn, wait)
     }
     function personnelSearch () {
-      let arr = stageShow.value.definedData
+      let arr =  stageShow.value.state ? stageShow.value.definedData:adminSchoold.value.data
       let newArr = arr.filter((item) => {
         // return (item.name && item.name.includes(filterText.value)) || (item.mobile && item.mobile.includes(filterText.value)) || (item.mobile && item.mobile.tmdId.includes(filterText.value))
         return item.name.includes(schoolSearch.value) || item.id.includes(schoolSearch.value)
       })
-      stageShow.value.definedData = newArr
+      stageShow.value.state ? stageShow.value.definedData = newArr:adminSchoold.value.data=newArr
     }
     //学区内某个管理员关联的学校
     function admintheSchool(id,index){
@@ -1030,7 +1030,7 @@ export default {
       let data={tmdId:id,areaId:currentlySelect.value.id}
       proxy.$api.adminRelevanceschool(data).then((res)=>{
         console.log(res,'管理返回')
-        res.state === 200 ? adminSchoold.value.data=res.mScInfos:''
+        res.state === 200 ? (adminSchoold.value.data=res.mScInfos,adminSchoold.value.original=res.mScInfos):''
       }).catch((error)=>{
         ElMessage.error('API异常,加载管理员管理学校列表失败')
       })
@@ -1045,11 +1045,11 @@ export default {
           (cutbtnTitle.value.icon = '#icon-chakan2'))
     })
     watch(schoolSearch, (newdata) => {
-      console.log('11111')
+      console.log(stageShow.value.state,'现在state的值')
       if (newdata.trim().length !== 0) {
         debounce(personnelSearch, 500)
       } else {
-        stageShow.value.definedData = stageShow.value.original
+        stageShow.value.state ? stageShow.value.definedData = stageShow.value.original : adminSchoold.value.data=adminSchoold.value.original
       }
     })
     return {
@@ -1941,6 +1941,6 @@ export default {
   display: block;
 }
 .stagebox-btns div button{
-  width:50%;
+  width:65%;
 }
 </style>

+ 72 - 15
TEAMModelBI/ClientApp/src/view/areamanage/statistics.vue

@@ -66,17 +66,47 @@
     <div class="areaList">
       <p class="commonbox-title arealists">区域列表</p>
       <div class="area-listinfo" v-loading="loadingTotal.areaList" element-loading-background="rgba(0, 0, 0, 0.3)">
-        <div class="area-item" v-for="(item,index) in areaLists" :key="item.id">
-          <div class="area-item-list">
-            <p class="area-item-name">{{item.name}}</p>
-            <p class="area-item-school"><span class="area-item-school-title">学区学校数:</span><span class="area-item-school-content">{{item.scCnt}}</span></p>
+        <el-tabs type="border-card">
+          <el-tab-pane label="学区">
+            <div class="area-data">
+              <div class="area-item" v-for="(item,index) in areaLists" :key="item.id">
+              <div class="area-item-list">
+              <p class="area-item-name">{{item.name}}</p>
+              <p class="area-item-school"><span class="area-item-school-title">学区学校数:</span><span class="area-item-school-content">{{item.scCnt}}</span></p>
             <!-- <p class="area-item-school"><span class="area-item-school-title">学区教师数:</span><span class="area-item-school-content">{{item.tchCnt}}</span></p>
             <p class="area-item-school"><span class="area-item-school-title">学区学生数:</span><span class="area-item-school-content">{{item.stuCnt}}</span></p> -->
-          </div>
-          <div class="item-detailsbtn" @click="getSchoolDistrict(item)">
-            <span>详情 ></span>
-          </div>
-        </div>
+              </div>
+              <div class="item-detailsbtn" @click="getSchoolDistrict(item)">
+              <span>详情 ></span>
+              </div>
+            </div>
+            </div>
+          </el-tab-pane>
+          <el-tab-pane label="未归区学校">
+            <div class="not-classify">
+              <el-table :data="notClassifydata" style="width:100%" height="300" empty-text="暂无数据">
+            <el-table-column label="校徽" align="center">
+              <template #default="scope">
+                <div class="school-badge">
+                  <el-image :src="scope.row.picture" fit="fill" />
+                </div>
+              </template>
+            </el-table-column>
+            <el-table-column prop="name" label="名称" align="center" />
+            <el-table-column prop="id" label="简码" align="center" />
+            <el-table-column prop="size" label="空间" align="center" />
+            <el-table-column align="center">
+              <template #header>
+                <el-input v-model="areaSearchValue" size="small" placeholder="搜索学校名称/简码" clearable />
+              </template>
+              <template #default="scope">
+                <el-button type="primary" size="small" @click="detailsclick(scope.row)">详情</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
       </div>
     </div>
   </div>
@@ -344,6 +374,8 @@ export default {
       classLine: true,
       areaList: true,
     })
+    let notClassifydata=ref([])
+    let notClassifyoriginal=ref({})
     let schooltableData = ref([])
     //某个学区顾问列表
     let CounselorList = ref([])
@@ -1429,6 +1461,7 @@ export default {
             getClassData()
             getclassification()
             getAllList()
+            notclassify()
           }
         })
         .catch((res) => {
@@ -1565,6 +1598,15 @@ export default {
           ElMessage.error('全区课例活跃度获取异常')
         })
     }
+    //获取未归学区的学校列表
+    function notclassify(){
+      proxy.$api.getAreaSchoolList({}).then((res)=>{
+        console.log(res,'未归区的学校')
+        res.state === 200 ? (notClassifydata.value=res.areaSchool,notClassifyoriginal.value=res.areaSchool):''
+      }).catch((error)=>{
+        ElMessage.error('API异常,获取未归区学校列表失败')
+      })
+    }
     //获取某个学区的数据统计包含跳转
     function getSchoolDistrict (areaids) {
       console.log(areaids, 'ID!!!!!')
@@ -1814,12 +1856,12 @@ export default {
       timer.value = setTimeout(fn, wait)
     }
     function personnelSearch () {
-      let arr = schooltableData.value
+      let arr = showPattern.value==='all'? notClassifydata.value:schooltableData.value
       let newArr = arr.filter((item) => {
         // return (item.name && item.name.includes(filterText.value)) || (item.mobile && item.mobile.includes(filterText.value)) || (item.mobile && item.mobile.tmdId.includes(filterText.value))
         return item.name.includes(areaSearchValue.value) || item.id.includes(areaSearchValue.value)
       })
-      schooltableData.value = newArr
+      showPattern.value==='all'?  notClassifydata.value=newArr:schooltableData.value = newArr
     }
     getAll()
     // getoption()
@@ -1830,7 +1872,7 @@ export default {
       if (newdata.trim().length !== 0) {
         debounce(personnelSearch, 500)
       } else {
-        schooltableData.value = originalSchool.value
+        showPattern.value==='all'? notClassifydata.value=notClassifyoriginal.value:schooltableData.value = originalSchool.value
       }
     })
     return {
@@ -1865,7 +1907,10 @@ export default {
       timer,
       personnelSearch,
       originalSchool,
-      unit
+      unit,
+      notclassify,
+      notClassifydata,
+      notClassifyoriginal
     }
   },
 }
@@ -2225,7 +2270,7 @@ export default {
 }
 .area-listinfo {
   width: 100%;
-  height: 300px;
+  height: 450px;
   background: #fff;
   padding: 1%;
   /* height: 40vh; */
@@ -2234,7 +2279,7 @@ export default {
   flex-wrap: wrap;
   flex-direction: row;
   justify-content: flex-start;
-  overflow: auto;
+  /* overflow: auto; */
 }
 .area-item {
   width: 18%;
@@ -2412,6 +2457,17 @@ export default {
   width: 100%;
   text-align: center;
 }
+.area-data{
+  width:100%;
+  height:25vh;
+  display: flex;
+  flex-wrap: wrap;
+  overflow: auto;
+}
+.not-classify{
+  width:100%;
+  height:25vh;
+}
 </style>
 
 <style>
@@ -2419,4 +2475,5 @@ export default {
 .statisticsbox .el-loading-spinner .circular {
   display: inline !important;
 }
+.area-listinfo .el-tabs{width:100%}
 </style>

+ 122 - 38
TEAMModelBI/ClientApp/src/view/created/created.vue

@@ -287,7 +287,7 @@
             <el-table-column prop="city" :label="$t(`areaManages.selector.cityName`)" align="center" />
             <el-table-column prop="dist" :label="$t(`areaManages.selector.areaName`)" align="center" />
             <el-table-column prop="address" :label="$t(`schoolManages.createSchools.schoolinfo.address`)" align="center" />
-            <el-table-column prop="state" label="数据状态" align="center">
+            <el-table-column prop="state" label="数据状态" align="center" v-if="batchTablesArr ===true">
               <template #default="scope">
                 <div class="normal" v-if="scope.row.dataState ===true">
                   <div>
@@ -319,15 +319,20 @@
             </el-table-column>
           </el-table>
           <div class="batchs-btn">
-            <el-button type="primary" size="medium" @click="quantity()" :loading="createdSchoolLoading" v-if="batchCreatedSchool===false && batchTablesArr">
+            <el-button type="primary" size="medium" @click="quantity()" :loading="createdSchoolLoading" v-if="batchCreatedSchool===false && batchTablesArr && verifyState">
               {{ $t(`schoolManages.createSchools.batchBtn`) }}
             </el-button>
-            <el-button type="primary" size="medium" disabled v-else-if="batchCreatedSchool===false && batchTablesArr ===false">
-              {{ $t(`schoolManages.createSchools.batchBtn`) }}
+            <el-button type="info" size="medium"  v-else-if="batchCreatedSchool===false && batchTablesArr && verifyState===false" disabled>
+                    批量建立学校
+            </el-button>
+            <el-button type="primary" size="medium"  v-else-if="batchCreatedSchool===false && batchTablesArr ===false" @click="verifyData">
+              <!-- {{ $t(`schoolManages.createSchools.batchBtn`) }} -->
+              数据验证
             </el-button>
             <el-button type="primary" size="medium" @click="batchList=false,batchCreatedSchool=false,batchData=[]" v-else-if="batchCreatedSchool===true">
               确认
             </el-button>
+            <span v-if="batchCreatedSchool===false && batchTablesArr && verifyState===false" class="error-int">请完善表格,重新提交</span>
           </div>
         </div>
       </div>
@@ -499,6 +504,7 @@ export default {
     let batchCreatedResult = ref()
     let allSchool = ref([])
     let batchTablesArr = ref(true)
+    let verifyState=ref(true)
     onMounted(() => {
       formArea.value = JSON.parse(JSON.stringify(areaData))
       console.log(formArea, '初步的数据')
@@ -720,9 +726,16 @@ export default {
       let users = JSON.parse(localStorage.getItem('userData'))
       console.log(schoolForm.value)
       for (let i in schoolForm.value) {
+        console.log(schoolForm.value[i].presupposeAdmin)
+        let adminArr=''
+        if(schoolForm.value[i].presupposeAdmin.includes(',')){
+          adminArr=schoolForm.value[i].presupposeAdmin.split(',')
+        }else if(schoolForm.value[i].presupposeAdmin.includes(',')){
+          adminArr=schoolForm.value[i].presupposeAdmin.split(',')
+        }
         datas.push({
           name: schoolForm.value[i].name,
-          admin: schoolForm.value[i].presupposeAdmin,
+          admin: adminArr ? adminArr:schoolForm.value[i].presupposeAdmin,
           period: schoolForm.value[i].radio1,
           size: parseInt(schoolForm.value[i].pitchSpace),
           region: '中国',
@@ -817,30 +830,31 @@ export default {
         //     return
         //   }
         // }
-        console.log(allSchool)
-        let schoolLists = [];
-        results.forEach((item) => { schoolLists.push(item.name); item.dataState = true })
-        let resultSchoolList = isRepeat(schoolLists)
-        console.log(resultSchoolList)
-        resultSchoolList !== false ?
-          (results[resultSchoolList].dataState = false, results[resultSchoolList].abnormaltext = '列表中此学校已重复', results[resultSchoolList].class = 'anomaly', batchTablesArr.value = false)
-          : ''
-        if (resultSchoolList !== false) {
-          let repetitionData = results[resultSchoolList].name
-          results.forEach((x) => { x.name === repetitionData ? (x.dataState = false, x.abnormaltext = '列表中此学校已重复', x.class = 'anomaly') : '' })
-        }
-        for (let s in results) {
-          let schoolname = results[s].name
-          // results[s].dataState = true
-          for (let e in allSchool.value) {
-            if (allSchool.value[e].name === schoolname) {
-              results[s].dataState = false
-              results[s].abnormaltext = '已存在此学校,请勿重新创建'
-              results[s].class = 'anomaly'
-              batchTablesArr.value = false
-            }
-          }
-        }
+        // console.log(allSchool)
+        // let schoolLists = [];
+        // results.forEach((item) => { schoolLists.push(item.name); item.dataState = true })
+        // let resultSchoolList = isRepeat(schoolLists)
+        // console.log(resultSchoolList)
+        // resultSchoolList !== false ?
+        //   (results[resultSchoolList].dataState = false, results[resultSchoolList].abnormaltext = '列表中此学校已重复', results[resultSchoolList].class = 'anomaly', batchTablesArr.value = false)
+        //   : ''
+        // if (resultSchoolList !== false) {
+        //   let repetitionData = results[resultSchoolList].name
+        //   results.forEach((x) => { x.name === repetitionData ? (x.dataState = false, x.abnormaltext = '列表中此学校已重复', x.class = 'anomaly') : '' })
+        // }
+        // for (let s in results) {
+        //   let schoolname = results[s].name
+        //   // results[s].dataState = true
+        //   for (let e in allSchool.value) {
+        //     if (allSchool.value[e].name === schoolname) {
+        //       results[s].dataState = false
+        //       results[s].abnormaltext = '已存在此学校,请勿重新创建'
+        //       results[s].class = 'anomaly'
+        //       batchTablesArr.value = false
+        //     }
+        //   }
+        // }
+        batchTablesArr.value = false
         console.log(results, '导入结果')
         let standardSory = standard.sort()
         let headers = header.sort()
@@ -850,8 +864,8 @@ export default {
           results.forEach((item) => {
             var stringResult = item.period.split('、')
             item.period = stringResult
-            item.admin = item.hasOwnProperty('admin') ? item.admin.toString() : ''
-            item.areaId = item.areaid
+            item.admin = item.hasOwnProperty('admin') ? (item.admin.toString()).trim() : ''
+            item.areaId = item.areaid ? item.areaid:''
             delete item.areaid
           })
           batchData.value.push(...results)
@@ -862,11 +876,25 @@ export default {
         }
       }
     }
-    //确定批量创校
-    function quantity () {
-      let users = JSON.parse(localStorage.getItem('userData'))
-      let schoolData = batchData.value
-      console.log(schoolData, '批量的数据')
+    //批量创校 数据验证
+    function verifyData(){
+      let batchDatas=batchData.value
+      let schoolData=batchData.value
+      let scName=[];let scAdmin=[];let scAreaid=[]
+      batchDatas.forEach((item)=>{
+        item.name ? scName.push(item.name.toString()):''
+        // item.admin  && (item.admin.indexOf(',') ==-1 || item.admin.indexOf(',') ==-1)? scAdmin.push(item.admin.toString()):''
+        item.areaId ? scAreaid.push(item.areaId.toString()):''
+        if(item.admin.includes(',')){
+          let adminA=item.admin.split(',')
+          scAdmin=scAdmin.concat(adminA)
+        }else if(item.admin.includes(',')){
+          let adminA=item.admin.split(',')
+          scAdmin=scAdmin.concat(adminA)
+        }else{
+          scAdmin.push(item.admin.toString())
+        }
+      })
       for (let i in schoolData) {
         console.log(schoolData)
         let ids = MathRand()
@@ -889,7 +917,55 @@ export default {
           return
         }
       }
+      let data={scNames:scName,accounts:scAdmin,areaIds:scAreaid}
+      proxy.$api.verifyContent(data).then((res)=>{
+        console.log(res,'数据验证的结果')
+        res.state === 200 ? (batchTablesArr.value=true,batchDatas.forEach((item)=>{item.dataState=true})):''
+        if(res.state ===201){
+          batchTablesArr.value=true;verifyState.value=false
+          batchDatas.forEach((item)=>{item.dataState=true})
+          if(res.existScNames.length !==0){
+             for(let i in res.existScNames){
+               let name=res.existScNames[i]
+               for(let n in batchDatas){
+                batchDatas[n].name===name ? (batchDatas[n].abnormaltext='该学校名称已存在',batchDatas[n].class = 'anomaly',batchDatas[n].dataState=false):''
+               }
+             }
+          }else if(res.noAccounts.length !==0){
+            for(let i in res.noAccounts){
+               let admins=res.noAccounts[i]
+               for(let n in batchDatas){
+                batchDatas[n].admin===admins ? (batchDatas[n].abnormaltext='当前创建管理员用户不存在',batchDatas[n].class = 'anomaly',batchDatas[n].dataState=false):''
+               }
+             }
+          }else if(res.noAreaIds.length !==0){
+            for(let i in res.noAreaIds){
+               let areaIdx=res.noAreaIds[i]
+               for(let n in batchDatas){
+                batchDatas[n].areaId==areaIdx ? (batchDatas[n].abnormaltext='创建学校所归属学区ID异常',batchDatas[n].class = 'anomaly',batchDatas[n].dataState=false):''
+               }
+            }
+          }
+        }
+      }).catch((error)=>{
+        ElMessage.error('API异常,数据验证失败')
+      })
+    }
+    //确定批量创校
+    function quantity () {
+      let users = JSON.parse(localStorage.getItem('userData'))
+      let schoolData = batchData.value
+      console.log(schoolData, '批量的数据')
       createdSchoolLoading.value = true
+      for(let n in schoolData){
+        if(schoolData[n].admin.includes(',')){
+          schoolData[n].admin=schoolData[n].admin.split(",")
+        }else if(schoolData[n].admin.includes(',')){
+          schoolData[n].admin=schoolData[n].admin.split(",")
+        }else{
+          schoolData[n].admin=[schoolData[n].admin]
+        }
+      }
       console.log(schoolData, '处理ID后')
       let datas = { tmdId: users.tmdId, tmdName: users.tmdName, biSchools: schoolData, lang: 'zh-CN' }
       console.log(datas, '批量最后的数据')
@@ -901,6 +977,7 @@ export default {
           ElMessage.success(proxy.$t(`commonMsg.batchCreatedSuccess`))
           // batchList.value = false;
           // batchData.value = []; 
+          ElMessage.success('批量创建成功')
           router.push({ path: '/home/schoolmanage' })
         } else if (res.state === 201) {
           console.log(batchData.value, '值!!!')
@@ -1019,7 +1096,7 @@ export default {
     //下载批量创校模板
     function downloadModel () {
       window.location.href =
-        'https://teammodeltest.blob.core.chinacloudapi.cn/download/BIDefaultFile%2F%E6%89%B9%E9%87%8F%E5%88%9B%E6%A0%A1%E6%A8%A1%E6%9D%BF%2F%E6%89%B9%E9%87%8F%E5%88%9B%E6%A0%A1%E6%A8%A1%E7%89%88-%E7%AE%80%E4%BD%93.xlsx'
+        'https://teammodeltest.blob.core.chinacloudapi.cn/download/BIDefaultFile%2F%E6%89%B9%E9%87%8F%E5%88%9B%E6%A0%A1%E6%A8%A1%E6%9D%BF%2F%E6%89%B9%E9%87%8F%E5%88%9B%E6%A0%A1%E6%A8%A1%E7%89%88.xlsx'
     }
     //所有学校列表
     function getAllschool () {
@@ -1090,7 +1167,9 @@ export default {
       allSchool,
       batchTablesArr,
       isRepeat,
-      createdAreds
+      createdAreds,
+      verifyData,
+      verifyState
     }
   },
 }
@@ -1396,6 +1475,11 @@ export default {
 .repetition {
   color: red;
 }
+.error-int{
+  font-size:14px;
+  color:red;
+  margin-left:1%;
+}
 </style>
 <style>
 .areabox .el-form {

+ 21 - 9
TEAMModelBI/Controllers/BINormal/AreaRelevantController.cs

@@ -11,6 +11,7 @@ using System.Text.Json;
 using System.Threading.Tasks;
 using TEAMModelBI.Filter;
 using TEAMModelBI.Models;
+using TEAMModelBI.Tool;
 using TEAMModelBI.Tool.Extension;
 using TEAMModelOS.Models;
 using TEAMModelOS.SDK;
@@ -415,6 +416,7 @@ namespace TEAMModelBI.Controllers.BINormal
             return Ok(new { state = RespondCode.Ok, teacher });
         }
 
+
         /// <summary>
         /// 通过区域ID查询学校列表   //已对接
         /// </summary>
@@ -424,7 +426,7 @@ namespace TEAMModelBI.Controllers.BINormal
         [HttpPost("get-schools")]
         public async Task<IActionResult> GetSchools(JsonElement jsonElement) 
         {
-            if (!jsonElement.TryGetProperty("areaId", out JsonElement areaId)) return BadRequest();
+            jsonElement.TryGetProperty("areaId", out JsonElement areaId);
             //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
 
             var cosmosClient = _azureCosmos.GetCosmosClient();
@@ -434,8 +436,13 @@ namespace TEAMModelBI.Controllers.BINormal
 
             List<AreaSchool> areaSchool = new();
 
-            string areaScSql = $"select c.id,c.name,c.picture,c.size,c.areaId,c.scale from c where c.areaId='{areaId}'";
-            await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<AreaSchool>(queryText: areaScSql,requestOptions:new QueryRequestOptions() { PartitionKey = new PartitionKey("Base")}))
+            StringBuilder areaScSql = new($"select c.id,c.name,c.picture,c.size,c.areaId,c.scale from c");
+            if (!string.IsNullOrEmpty($"{areaId}")) 
+                areaScSql.Append($" where c.areaId='{areaId}'");
+            else
+                areaScSql.Append(" where c.areaId = null or c.areaId = ''");
+
+            await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<AreaSchool>(queryText: areaScSql.ToString(),requestOptions:new QueryRequestOptions() { PartitionKey = new PartitionKey("Base")}))
             {
                 areaSchool.Add(item);
             }
@@ -473,7 +480,7 @@ namespace TEAMModelBI.Controllers.BINormal
         [HttpPost("get-assists")]
         public async Task<IActionResult> GetAssists(JsonElement jsonElement)
         {
-            if (!jsonElement.TryGetProperty("areaId", out JsonElement areaId)) return BadRequest();
+            jsonElement.TryGetProperty("areaId", out JsonElement areaId);
             //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
 
             var cosmosClient = _azureCosmos.GetCosmosClient();
@@ -491,12 +498,17 @@ namespace TEAMModelBI.Controllers.BINormal
             List<string> scIds = new();
             HashSet<string> tchIds = new();
 
-            string scIdsSql = $"select value(c.id) from c where c.areaId='{areaId}'";
+            string scIdsSql = null;
+            if (!string.IsNullOrEmpty($"{areaId}"))
+                scIdsSql = $"select value(c.id) from c where c.areaId='{areaId}'";
+            else
+                scIdsSql = "select value(c.id) from c where c.areaId = null or c.areaId = ''";
+            scIds = await CommonFind.GetValueSingle(cosmosClient, "School", scIdsSql, "Base");
 
-            await foreach (var itemId in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<string>(queryText: scIdsSql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") })) 
-            {
-                scIds.Add(itemId);
-            }
+            //await foreach (var itemId in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<string>(queryText: scIdsSql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") })) 
+            //{
+            //    scIds.Add(itemId);
+            //}
 
             foreach (var scId in scIds)
             {

+ 14 - 1
TEAMModelBI/Controllers/BISchool/BatchSchoolController.cs

@@ -1074,7 +1074,20 @@ namespace TEAMModelBI.Controllers.BISchool
 
                 accounts.ForEach(ac =>
                 {
-                    var noTmdInfo = tmdInfos.Find(f => f.id.Equals($"{ac}") || f.mail.Equals($"{ac}") || f.mobile.Equals($"{ac}"));
+                    TmdUserinfo noTmdInfo = null;
+                    tmdInfos.ForEach(tmd =>
+                    {
+                        if (!string.IsNullOrEmpty(tmd.id))
+                            if (tmd.id.Equals($"{ac}")) 
+                                noTmdInfo = tmd;
+                        if (!string.IsNullOrEmpty(tmd.mobile))
+                            if (tmd.mobile.Equals($"{ac}")) 
+                                noTmdInfo = tmd;
+                        if (!string.IsNullOrEmpty(tmd.mail))
+                            if (tmd.mail.Equals($"{ac}"))
+                                noTmdInfo = tmd;
+                    });
+                    //noTmdInfo = tmdInfos.Find(f => f.id.Equals($"{ac}") || f.mail.Equals($"{ac}") || f.mobile.Equals($"{ac}"));
                     if (noTmdInfo == null)
                         noAccounts.Add(ac);
                 });

+ 9 - 8
TEAMModelBI/Controllers/Census/ActivitySticsController.cs

@@ -66,13 +66,20 @@ namespace TEAMModelBI.Controllers.Census
                 if (!string.IsNullOrEmpty($"{areaId}"))
                 {
                     string areaSc = $"select value(c.id) from c where c.pk='School' and c.areaId='{areaId}'";
-                    await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<string>(queryText: areaSc, requestOptions: new QueryRequestOptions() { })) 
+                    await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<string>(queryText: areaSc, requestOptions: new QueryRequestOptions() { }))
                     {
                         scIds.Add(item);
                     }
 
                     inSql = $" and {BICommonWay.ManyScSql("c.school", scIds)}";
                 }
+                else
+                {
+                    string scSql = "select value(c.id) from c where c.areaId = null or c.areaId = ''";
+                    scIds = await CommonFind.GetValueSingle(cosmosClient, "School", scSql, "Base");
+                    inSql = $" and {BICommonWay.ManyScSql("c.school", scIds)}";
+                }
+
 
                 foreach (var type in StaticValue.activityTypes)
                 {
@@ -159,9 +166,7 @@ namespace TEAMModelBI.Controllers.Census
             int carryOnCount = 0;   //进行中
             int noCount = 0;      //未开始
             List<AreaStudy> trains = new();
-
-            AreaSetting setting = null;
-           
+            AreaSetting setting = null;           
 
             string oftenSql = "select value(count(c.id)) from c";
             string scSql = "";
@@ -648,7 +653,6 @@ namespace TEAMModelBI.Controllers.Census
             return Ok(new {state = RespondCode.Ok, allLess, weekLess, termLess, monthLessCnt, actAllCnt, actWeekCnt, actTermCnt, actMonthCnt });
         }
 
-
         /// <summary>
         /// 统计活动 传醍摩豆则查询相关的学校活动
         /// </summary>
@@ -948,7 +952,6 @@ namespace TEAMModelBI.Controllers.Census
             //public int stuCnt { get; set; } = 0;
         }
 
-
         public class AreaStudy 
         {
             public string id { get; set; }
@@ -972,7 +975,6 @@ namespace TEAMModelBI.Controllers.Census
             /// 必修的
             /// </summary>
             public Currency currency { get; set; } = new Currency();
-
         }
 
         private class SchoolInfo
@@ -991,7 +993,6 @@ namespace TEAMModelBI.Controllers.Census
             public List<KeyValuePair<object, long>> census { get; set; } = new List<KeyValuePair<object, long>>();
         }
 
-
         private record SchoolLesson
         {
             public string id { get; set; }

+ 10 - 1
TEAMModelBI/Controllers/Census/BlobLogController.cs

@@ -48,6 +48,7 @@ namespace TEAMModelBI.Controllers.Census
         {
             //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
             jsonElement.TryGetProperty("areaId", out JsonElement areaId);
+            jsonElement.TryGetProperty("isJoin", out JsonElement isJoin);
             var cosmosClient = _azureCosmos.GetCosmosClient();
             ////分开部署,就不需要,一站多用时,取消注释
             //if ($"{site}".Equals(BIConst.Global))
@@ -93,6 +94,14 @@ namespace TEAMModelBI.Controllers.Census
             }
             else
             {
+                StringBuilder scSql = new("select value(c.id) from c");
+                if ($"{isJoin}".Equals("noJoin")) 
+                {
+                    scSql.Append($" where c.areaId = null or c.areaId = ''");
+                }
+
+                schoolIds = await CommonFind.GetValueSingle(cosmosClient, "School",scSql.ToString(), "Base");
+
                 foreach (var item in StaticValue.fileType)
                 {
                     string typeSql = $"select value(count(c.id)) from c where c.pk='Bloblog' and c.type='{item}'";
@@ -101,7 +110,7 @@ namespace TEAMModelBI.Controllers.Census
                     typeCnt.Add(item, fileCnt);
                     recCount += fileCnt;
                 }
-                schoolIds = await CommonFind.FindSchoolIds(cosmosClient, $"select c.id from c", "Base");
+
                 foreach (var id in schoolIds)
                 {
                     long blobsize = 0;

+ 16 - 6
TEAMModelBI/Controllers/Census/LessonSticsController.cs

@@ -55,7 +55,7 @@ namespace TEAMModelBI.Controllers.Census
         [HttpPost("get-schoolan")]
         public async Task<IActionResult> GetSchoolsAn(JsonElement jsonElement)
         {
-            if (!jsonElement.TryGetProperty("areaId", out JsonElement areaId)) return BadRequest();
+            jsonElement.TryGetProperty("areaId", out JsonElement areaId);
             //jsonElement.TryGetProperty("site", out JsonElement site); //分开部署,就不需要,一站多用时,取消注释
             var (lWeekS, lWeekE) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "week");
             var (monthS, monthE) = TimeHelper.GetStartOrEnd(DateTimeOffset.UtcNow, "month");
@@ -66,7 +66,14 @@ namespace TEAMModelBI.Controllers.Census
             //    cosmosClient = _azureCosmos.GetCosmosClient(name: BIConst.Global);
 
             List<AreaSchools> areaSchools = new();
-            await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<AreaSchools>(queryText: $"select c.id,c.name,c.picture from c where c.areaId='{areaId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base")}))
+
+            StringBuilder scSql = new("select c.id,c.name,c.picture from c ");
+            if (!string.IsNullOrEmpty($"{areaId}"))
+                scSql.Append($" where c.areaId='{areaId}'");
+            else
+                scSql.Append($" where c.areaId = null or c.areaId = ''");
+
+            await foreach (var item in cosmosClient.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<AreaSchools>(queryText: scSql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base")}))
             {
                 areaSchools.Add(item);
             }
@@ -94,6 +101,7 @@ namespace TEAMModelBI.Controllers.Census
         public async Task<IActionResult> GetWeekCount(JsonElement jsonElement)
         {
             jsonElement.TryGetProperty("areaId", out JsonElement areaId);
+            jsonElement.TryGetProperty("isJoin", out JsonElement isJoin);
             //jsonElement.TryGetProperty("site", out JsonElement site);//分开部署,就不需要,一站多用时,取消注释
 
             //Dictionary<int, double> weeks = new();
@@ -112,13 +120,15 @@ namespace TEAMModelBI.Controllers.Census
             List<LessonCount> scount = new();
             List<LessonCount> tcount = new();
 
-            StringBuilder sqlTxt = new("select c.id from c");
+            StringBuilder sqlTxt = new("select value(c.id) from c");
             if (!string.IsNullOrEmpty($"{areaId}"))
-            {
                 sqlTxt.Append($" where c.areaId='{areaId}'");
+            else 
+            {
+                if ($"{isJoin}".Equals("noJoin"))
+                    sqlTxt.Append($" where c.areaId = null or c.areaId = ''");
             }
-
-            List<string> schools = await CommonFind.FindSchoolIds(cosmosClient, sqlTxt.ToString(), "Base");
+            List<string> schools = await CommonFind.GetValueSingle(cosmosClient, "School",sqlTxt.ToString(), "Base");
 
             foreach (var sId in schools)
             {

+ 12 - 51
TEAMModelBI/Controllers/Census/SchoolController.cs

@@ -14,6 +14,7 @@ using TEAMModelBI.Tool;
 using TEAMModelBI.Tool.CosmosBank;
 using TEAMModelOS.Models;
 using TEAMModelOS.SDK.Context.BI;
+using TEAMModelOS.SDK.Context.Constant;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models;
@@ -358,7 +359,7 @@ namespace TEAMModelBI.Controllers.Census
 
 
         /// <summary>
-        /// 未区域学校统计    未写完
+        /// 未区域学校统计   
         /// </summary>
         /// <param name="jsonElement"></param>
         /// <returns></returns>
@@ -389,7 +390,7 @@ namespace TEAMModelBI.Controllers.Census
         }
         
         /// <summary>
-        /// 未加区的学校统计详细
+        /// 未加区的学校统计
         /// </summary>
         /// <param name="jsonElement"></param>
         /// <returns></returns>
@@ -407,41 +408,10 @@ namespace TEAMModelBI.Controllers.Census
 
             List<AreaAssist> areaAssists = new();  //顾问信息
 
-            int scCnt = 0; //学校人数
-            int weekScCnt = 0; //本周学校人数
-            int motnhScCnt = 0; //本月学校人数
-
             int tchCnt = 0;   //所有区级老师
-            int weekTchCnt = 0;   //所有区级老师
-            int monthTchCnt = 0;   //所有区级老师
-
             int stuCnt = 0;   //所有区级学生
-            int weekStuCnt = 0;   //所有区级学生
-            int monthStuCnt = 0;   //所有区级学生
-
-            int areaSize = 0;   //区级空间
-            int weekSize = 0;   //本周空间
-            int monthSize = 0;   //本月空间
-
-            int allLess = 0; //所有课例
-            int weekLess = 0;  //周课例
-            int monthLess = 0;  //月课例
-            int termLess = 0;    //学期课例
-
-            int totalTime = 0;   //累计学时
-            int allActCnt = 0;   //所有活动
-            int weekActivity = 0; //周活动数量
-            int monthActCnt = 0; //月活动数量
-            int termActivity = 0;   //学期活动
-
-            int onLineCount = 0;    //线上研修人数
-            int offlineCount = 0;   //线下研修人数
-            int classRoomCount = 0;  //课堂实录人数
-            int submitCount = 0;     //认证材料人数
-
-            int fulfilCount = 0;    //已完成
-            int carryOnCount = 0;   //进行中
-            int noCount = 0;      //未开始
+            int tLessCnt = 0;  //课例数量
+            int tActCnt = 0;   //活动数量
 
             HashSet<string> tchIds = new();
             List<string> scIds = new(); //学校id集合
@@ -502,25 +472,16 @@ namespace TEAMModelBI.Controllers.Census
                 else { noIds.Add(item); }
             }
 
-            AreaSetting setting = new()
+            if (scIds.Count > 0)
             {
-                allTime = 50,
-                classTime = 5,
-                submitTime = 15,
-                onlineTime = 20,
-                offlineTime = 10,
-                lessonMinutes = 45,
-            };
-            string oftenSql = "select value(count(c.id)) from c";
-
-
-
-
-
-
+                string lesSql = $"select value(count(c.id)) from c where c.pk='LessonRecord' and {scsSql}";
+                tLessCnt = await CommonFind.GetSqlValueCount(cosmosClient, new List<string>() { "School", "Teacher" }, lesSql);
 
+                string  actComSql = BICommonWay.ManyScSql(" and c.school", scIds);
+                tActCnt = await ActivityWay.GetCnt(cosmosClient, condSql: actComSql);
+            }
 
-            return Ok(new { state = 200 });
+            return Ok(new { state = RespondCode.Ok, scCnt = scIds.Count, tchCnt, stuCnt, allCnt = tLessCnt + tActCnt, tLessCnt, tActCnt});
         }
 
 

+ 19 - 17
TEAMModelBI/Lang/en-us.json

@@ -1,18 +1,20 @@
-{
-  "request_school": [ "Apply to join school", "{tmdname}({tmdid}) applying to join {schooName}." ],  
-  "invite_school": [ "Invite to join school", "{schooName} has invited you to join." ], 
-  "remove_school": [ "Remove from school", "{schooName} removed you from the school's teacher list." ],  
-  "request-join_school": [ "Agree to join school", "{schooName} has agreed you to join the school." ], 
-  "invite-join_school": [ "Accepting join school invitation", "{tmdname} has accepted an invitation to join {schooName}." ], 
-  "coedit_syllabus": [ "Invite to co-edit syllabus", "{tmdname} invites you to co-edit school-based syllabus, Volume name: {volumeName}, Node name: {syllabusName}." ],  
-  "share_syllabus": [ "Receive shared syllabus", "{tmdname} shared personal syllabus with you, Volume name: {volumeName}, Node name: {syllabusName}." ],  
-  "transfer-admin_school": [ "Transfer administrator", "{tmdname} will transfer the administrator of {schooName} to you." ],  
-  "scoring-arb_school": [ "Assign arbitration exam scoring task", "{tmdname} of {schoolname} has assign you an arbitration exam scoring task." ],  
-  "scoring-err_school": [ "Assign abnormal exam paper grading task", "{tmdname} of {schoolname} has assign you an abnormal exam paper grading task." ],  
-  "scoring-mark_school": [ "Assign exam paper grading task", "{tmdname} of {schoolname} has assign you an exam paper grading task." ],  
-  "scan-join_groupList": [ "Join course notice", "{tmdname} join the {groupListName} course via QRcode scanning" ], 
-  "scan-join_school": [ "Join school notice", "{tmdname} join school, {schoolName}, via QRcode scanning" ],  
-  "submitanswer_homework": [ "Homework submission notice", "{tmdname} has submitted a homework({homeworkName})" ],  
-  "expire-school_lessonRecord": [ "Lesson record expiration notice", "Your lesson record, {lessonRecordName}, on {schoolname} will expire at {expireTime}" ],  
-  "expire-private_lessonRecord": [ "Lesson record expiration notice", "Your lesson record, {lessonRecordName} will expire at {expireTime}" ]  
+{
+  "request_school": [ "Apply to join school", "{tmdname}({tmdid}) applying to join {schoolName}." ],
+  "invite_school": [ "Invite to join school", "{schoolName} has invited you to join." ],
+  "remove_school": [ "Remove from school", "{schoolName} removed you from the school's teacher list." ],
+  "request-join_school": [ "Agree to join school", "{schoolName} has agreed you to join the school." ],
+  "invite-join_school": [ "Accepting join school invitation", "{tmdname} has accepted an invitation to join {schoolName}." ],
+  "coedit_syllabus": [ "Invite to co-edit syllabus", "{tmdname} of {schoolName} has invited you to co-edit school-based syllabus, Volume name: {volumeName}, Node name: {syllabusName}." ],
+  "coedit_volume": [ "Invite to co-edit volume", "{tmdname} of {schoolName} has invited  you to co-edit school-based volume,Volume name:{volumeName}." ],
+  "share_syllabus": [ "Receive shared syllabus", "{tmdname} shared personal syllabus with you, Volume name: {volumeName}, Node name: {syllabusName}." ],
+  "transfer-admin_school": [ "Transfer administrator", "{tmdname} will transfer the administrator of {schoolName} to you." ],
+  "scoring-arb_school": [ "Assign arbitration exam scoring task", "{tmdname} of {schoolName} has assign you an arbitration exam scoring task." ],
+  "scoring-err_school": [ "Assign abnormal exam paper grading task", "{tmdname} of {schoolName} has assign you an abnormal exam paper grading task." ],
+  "scoring-mark_school": [ "Assign exam paper grading task", "{tmdname} of {schoolName} has assign you an exam paper grading task." ],
+  "scan-join_groupList": [ "Join course notice", "{tmdname} join the {groupListName} course via QRcode scanning" ],
+  "scan-join_school": [ "Join school notice", "{tmdname} join school, {schoolName}, via QRcode scanning" ],
+  "submitanswer-school_homework": [ "Homework submission notice", "{tmdname} of {schoolName} has submitted a homework:{homeworkName}" ],
+  "submitanswer-private_homework": [ "Homework submission notice", "{tmdname} has submitted a homework({homeworkName})" ],
+  "expire-school_lessonRecord": [ "Lesson record expiration notice", "Your lesson record, {lessonName}, on {schoolName} will expire at {expireTime}" ],
+  "expire-private_lessonRecord": [ "Lesson record expiration notice", "Your lesson record, {lessonName} will expire at {expireTime}" ]
 }

+ 17 - 15
TEAMModelBI/Lang/zh-cn.json

@@ -1,18 +1,20 @@
-{
-  "request_school": [ "申请加入学校通知", "{tmdname}({tmdid})申请加入{schooName}。" ],
-  "invite_school": [ "邀请加入学校通知", "{schooName}邀请您加入学校。" ],
-  "remove_school": [ "从学校移除通知", "{schooName}将您从学校教师名单中移除。" ], 
-  "request-join_school": [ "同意申请加入学校通知", "{schooName}已同意您申请加入学校。" ],
-  "invite-join_school": [ "同意邀请加入学校通知", "{tmdname}已接受加入{schooName}的邀请。" ], 
-  "coedit_syllabus": [ "邀请共编课纲通知", "{tmdname}邀请你参与共编校本课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ], 
+{
+  "request_school": [ "申请加入学校通知", "{tmdname}({tmdid})申请加入{schoolName}。" ],
+  "invite_school": [ "邀请加入学校通知", "{schoolName}邀请您加入学校。" ],
+  "remove_school": [ "从学校移除通知", "{schoolName}将您从学校教师名单中移除。" ],
+  "request-join_school": [ "同意申请加入学校通知", "{schoolName}已同意您申请加入学校。" ],
+  "invite-join_school": [ "同意邀请加入学校通知", "{tmdname}已接受加入{schoolName}的邀请。" ],
+  "coedit_syllabus": [ "邀请共编课纲通知", "{schoolName}的{tmdname}邀请你参与共编校本课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ],
+  "coedit_volume": [ "邀请共编册别通知", "{schoolName}的{tmdname}邀请你参与共编校本册别,册别名称:{volumeName}。" ],
   "share_syllabus": [ "课纲分享接收通知", "{tmdname}向您分享了个人课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ],
-  "transfer-admin_school": [ "管理员移交通知", "{tmdname}将{schooName}的管理员移交给您。" ], 
-  "scoring-arb_school": [ "仲裁卷阅卷任务通知", "{schoolname}的{tmdname}向您发送了仲裁卷阅卷任务。" ], 
-  "scoring-err_school": [ "异常卷阅卷任务通知", "{schoolname}的{tmdname}向您发送了异常卷阅卷任务。" ],
-  "scoring-mark_school": [ "普通阅卷任务通知", "{schoolname}的{tmdname}向您发送了普通卷阅卷任务。" ],
-  "scan-join_groupList": [ "扫码加入名单通知", "{tmdname}扫码加入名单,名单:{groupListName}" ], 
+  "transfer-admin_school": [ "管理员移交通知", "{tmdname}将{schoolName}的管理员移交给您。" ],
+  "scoring-arb_school": [ "仲裁卷阅卷任务通知", "{schoolName}的{tmdname}向您发送了仲裁卷阅卷任务。" ],
+  "scoring-err_school": [ "异常卷阅卷任务通知", "{schoolName}的{tmdname}向您发送了异常卷阅卷任务。" ],
+  "scoring-mark_school": [ "普通阅卷任务通知", "{schoolName}的{tmdname}向您发送了普通卷阅卷任务。" ],
+  "scan-join_groupList": [ "扫码加入名单通知", "{tmdname}扫码加入名单,名单:{groupListName}" ],
   "scan-join_school": [ "扫码加入学校通知", "{tmdname}扫码加入学校,学校名称:{schoolName}" ],
-  "submitanswer_homework": [ "作业提交通知", "{tmdname}已提交作业,作业名称({homeworkName})" ], 
-  "expire-school_lessonRecord": [ "课例到期通知", "您在{schoolname}的课例将在{expireTime}到期,课例名称:{lessonRecordName}" ], 
-  "expire-private_lessonRecord": [ "课例到期通知", "您的课例将在{expireTime}到期,课例名称:{lessonRecordName}" ] 
+  "submitanswer-school_homework": [ "作业提交通知", "{schoolName}的{tmdname}已提交作业,作业名称:{homeworkName}" ],
+  "submitanswer-private_homework": [ "作业提交通知", "{tmdname}已提交作业,作业名称({homeworkName})" ],
+  "expire-school_lessonRecord": [ "课例到期通知", "您在{schoolName}的课例将在{expireTime}到期,课例名称:{lessonName}" ],
+  "expire-private_lessonRecord": [ "课例到期通知", "您的课例将在{expireTime}到期,课例名称:{lessonName}" ]
 }

+ 19 - 17
TEAMModelBI/Lang/zh-tw.json

@@ -1,18 +1,20 @@
-{
-  "request_school": [ "申请加入学校通知", "{tmdname}({tmdid})申请加入{schooName}。" ], 
-  "invite_school": [ "邀请加入学校通知", "{schooName}邀请您加入学校。" ], 
-  "remove_school": [ "从学校移除通知", "{schooName}将您从学校教师名单中移除。" ],  
-  "request-join_school": [ "同意申请加入学校通知", "{schooName}已同意您申请加入学校。" ],  
-  "invite-join_school": [ "同意邀请加入学校通知", "{tmdname}已接受加入{schooName}的邀请。" ],  
-  "coedit_syllabus": [ "邀请共编课纲通知", "{tmdname}邀请你参与共编校本课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ], 
-  "share_syllabus": [ "课纲分享接收通知", "{tmdname}向您分享了个人课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ], 
-  "transfer-admin_school": [ "管理员移交通知", "{tmdname}将{schooName}的管理员移交给您。" ],  
-  "scoring-arb_school": [ "仲裁卷阅卷任务通知", "{schoolname}的{tmdname}向您发送了仲裁卷阅卷任务。" ], 
-  "scoring-err_school": [ "异常卷阅卷任务通知", "{schoolname}的{tmdname}向您发送了异常卷阅卷任务。" ],  
-  "scoring-mark_school": [ "普通阅卷任务通知", "{schoolname}的{tmdname}向您发送了普通卷阅卷任务。" ],  
-  "scan-join_groupList": [ "扫码加入名单通知", "{tmdname}扫码加入名单,名单:{groupListName}" ],  
-  "scan-join_school": [ "扫码加入学校通知", "{tmdname}扫码加入学校,学校名称:{schoolName}" ],  
-  "submitanswer_homework": [ "作业提交通知", "{tmdname}已提交作业,作业名称({homeworkName})" ], 
-  "expire-school_lessonRecord": [ "课例到期通知", "您在{schoolname}的课例将在{expireTime}到期,课例名称:{lessonRecordName}" ],  
-  "expire-private_lessonRecord": [ "课例到期通知", "您的课例将在{expireTime}到期,课例名称:{lessonRecordName}" ]  
+{
+  "request_school": [ "申請加入學校通知", "{tmdname}({tmdid})申請加入{schoolName}。" ],
+  "invite_school": [ "邀請加入學校通知", "{schoolName}邀請您加入學校。" ],
+  "remove_school": [ "從學校移除通知", "{schoolName}將您從學校教師名單中移除。" ],
+  "request-join_school": [ "同意申請加入學校通知", "{schoolName}已同意您申請加入學校。" ],
+  "invite-join_school": [ "同意邀請加入學校通知", "{tmdname}已接受加入{schoolName}的邀請。" ],
+  "coedit_syllabus": [ "邀請共編課綱通知", "{schoolName}的{tmdname}邀請你參與共編校本課綱,冊別名稱:{volumeName},課綱節點名稱:{syllabusName}。" ],
+  "coedit_volume": [ "邀請共編冊別通知", "{schoolName}的{tmdname}邀請你參與共編校本冊別,冊別名稱:{volumeName}。" ],
+  "share_syllabus": [ "課綱分享接收通知", "{tmdname}向您分享了個人課綱,冊別名稱:{volumeName},課綱節點名稱:{syllabusName}。" ],
+  "transfer-admin_school": [ "管理員移交通知", "{tmdname}將{schoolName}的管理員移交給您。" ],
+  "scoring-arb_school": [ "仲裁卷閱卷任務通知", "{schoolName}的{tmdname}向您發送了仲裁卷閱卷任務。" ],
+  "scoring-err_school": [ "異常卷閱卷任務通知", "{schoolName}的{tmdname}向您發送了異常卷閱卷任務。" ],
+  "scoring-mark_school": [ "普通閱卷任務通知", "{schoolName}的{tmdname}向您發送了普通卷閱卷任務。" ],
+  "scan-join_groupList": [ "掃碼加入名單通知", "{tmdname}掃碼加入名單,名單:{groupListName}" ],
+  "scan-join_school": [ "掃碼加入學校通知", "{tmdname}掃碼加入學校,學校名稱:{schoolName}" ],
+  "submitanswer-school_homework": [ "作業提交通知", "{schoolName}的{tmdname}已提交作業,作業名稱:{homeworkName}" ],
+  "submitanswer-private_homework": [ "作業提交通知", "{tmdname}已提交作業,作業名稱({homeworkName})" ],
+  "expire-school_lessonRecord": [ "課例到期通知", "您在{schoolName}的課例將在{expireTime}到期,課例名稱:{lessonName}" ],
+  "expire-private_lessonRecord": [ "課例到期通知", "您的課例將在{expireTime}到期,課例名稱:{lessonName}" ]
 }

+ 19 - 17
TEAMModelOS.FunctionV4/Lang/en-us.json

@@ -1,18 +1,20 @@
-{
-  "request_school": [ "Apply to join school", "{tmdname}({tmdid}) applying to join {schooName}." ],  
-  "invite_school": [ "Invite to join school", "{schooName} has invited you to join." ], 
-  "remove_school": [ "Remove from school", "{schooName} removed you from the school's teacher list." ],  
-  "request-join_school": [ "Agree to join school", "{schooName} has agreed you to join the school." ], 
-  "invite-join_school": [ "Accepting join school invitation", "{tmdname} has accepted an invitation to join {schooName}." ], 
-  "coedit_syllabus": [ "Invite to co-edit syllabus", "{tmdname} invites you to co-edit school-based syllabus, Volume name: {volumeName}, Node name: {syllabusName}." ],  
-  "share_syllabus": [ "Receive shared syllabus", "{tmdname} shared personal syllabus with you, Volume name: {volumeName}, Node name: {syllabusName}." ],  
-  "transfer-admin_school": [ "Transfer administrator", "{tmdname} will transfer the administrator of {schooName} to you." ],  
-  "scoring-arb_school": [ "Assign arbitration exam scoring task", "{tmdname} of {schoolname} has assign you an arbitration exam scoring task." ],  
-  "scoring-err_school": [ "Assign abnormal exam paper grading task", "{tmdname} of {schoolname} has assign you an abnormal exam paper grading task." ],  
-  "scoring-mark_school": [ "Assign exam paper grading task", "{tmdname} of {schoolname} has assign you an exam paper grading task." ],  
-  "scan-join_groupList": [ "Join course notice", "{tmdname} join the {groupListName} course via QRcode scanning" ], 
-  "scan-join_school": [ "Join school notice", "{tmdname} join school, {schoolName}, via QRcode scanning" ],  
-  "submitanswer_homework": [ "Homework submission notice", "{tmdname} has submitted a homework({homeworkName})" ],  
-  "expire-school_lessonRecord": [ "Lesson record expiration notice", "Your lesson record, {lessonRecordName}, on {schoolname} will expire at {expireTime}" ],  
-  "expire-private_lessonRecord": [ "Lesson record expiration notice", "Your lesson record, {lessonRecordName} will expire at {expireTime}" ]  
+{
+  "request_school": [ "Apply to join school", "{tmdname}({tmdid}) applying to join {schoolName}." ],
+  "invite_school": [ "Invite to join school", "{schoolName} has invited you to join." ],
+  "remove_school": [ "Remove from school", "{schoolName} removed you from the school's teacher list." ],
+  "request-join_school": [ "Agree to join school", "{schoolName} has agreed you to join the school." ],
+  "invite-join_school": [ "Accepting join school invitation", "{tmdname} has accepted an invitation to join {schoolName}." ],
+  "coedit_syllabus": [ "Invite to co-edit syllabus", "{tmdname} of {schoolName} has invited you to co-edit school-based syllabus, Volume name: {volumeName}, Node name: {syllabusName}." ],
+  "coedit_volume": [ "Invite to co-edit volume", "{tmdname} of {schoolName} has invited  you to co-edit school-based volume,Volume name:{volumeName}." ],
+  "share_syllabus": [ "Receive shared syllabus", "{tmdname} shared personal syllabus with you, Volume name: {volumeName}, Node name: {syllabusName}." ],
+  "transfer-admin_school": [ "Transfer administrator", "{tmdname} will transfer the administrator of {schoolName} to you." ],
+  "scoring-arb_school": [ "Assign arbitration exam scoring task", "{tmdname} of {schoolName} has assign you an arbitration exam scoring task." ],
+  "scoring-err_school": [ "Assign abnormal exam paper grading task", "{tmdname} of {schoolName} has assign you an abnormal exam paper grading task." ],
+  "scoring-mark_school": [ "Assign exam paper grading task", "{tmdname} of {schoolName} has assign you an exam paper grading task." ],
+  "scan-join_groupList": [ "Join course notice", "{tmdname} join the {groupListName} course via QRcode scanning" ],
+  "scan-join_school": [ "Join school notice", "{tmdname} join school, {schoolName}, via QRcode scanning" ],
+  "submitanswer-school_homework": [ "Homework submission notice", "{tmdname} of {schoolName} has submitted a homework:{homeworkName}" ],
+  "submitanswer-private_homework": [ "Homework submission notice", "{tmdname} has submitted a homework({homeworkName})" ],
+  "expire-school_lessonRecord": [ "Lesson record expiration notice", "Your lesson record, {lessonName}, on {schoolName} will expire at {expireTime}" ],
+  "expire-private_lessonRecord": [ "Lesson record expiration notice", "Your lesson record, {lessonName} will expire at {expireTime}" ]
 }

+ 17 - 15
TEAMModelOS.FunctionV4/Lang/zh-cn.json

@@ -1,18 +1,20 @@
-{
-  "request_school": [ "申请加入学校通知", "{tmdname}({tmdid})申请加入{schooName}。" ],
-  "invite_school": [ "邀请加入学校通知", "{schooName}邀请您加入学校。" ],
-  "remove_school": [ "从学校移除通知", "{schooName}将您从学校教师名单中移除。" ], 
-  "request-join_school": [ "同意申请加入学校通知", "{schooName}已同意您申请加入学校。" ],
-  "invite-join_school": [ "同意邀请加入学校通知", "{tmdname}已接受加入{schooName}的邀请。" ], 
-  "coedit_syllabus": [ "邀请共编课纲通知", "{tmdname}邀请你参与共编校本课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ], 
+{
+  "request_school": [ "申请加入学校通知", "{tmdname}({tmdid})申请加入{schoolName}。" ],
+  "invite_school": [ "邀请加入学校通知", "{schoolName}邀请您加入学校。" ],
+  "remove_school": [ "从学校移除通知", "{schoolName}将您从学校教师名单中移除。" ],
+  "request-join_school": [ "同意申请加入学校通知", "{schoolName}已同意您申请加入学校。" ],
+  "invite-join_school": [ "同意邀请加入学校通知", "{tmdname}已接受加入{schoolName}的邀请。" ],
+  "coedit_syllabus": [ "邀请共编课纲通知", "{schoolName}的{tmdname}邀请你参与共编校本课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ],
+  "coedit_volume": [ "邀请共编册别通知", "{schoolName}的{tmdname}邀请你参与共编校本册别,册别名称:{volumeName}。" ],
   "share_syllabus": [ "课纲分享接收通知", "{tmdname}向您分享了个人课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ],
-  "transfer-admin_school": [ "管理员移交通知", "{tmdname}将{schooName}的管理员移交给您。" ], 
-  "scoring-arb_school": [ "仲裁卷阅卷任务通知", "{schoolname}的{tmdname}向您发送了仲裁卷阅卷任务。" ], 
-  "scoring-err_school": [ "异常卷阅卷任务通知", "{schoolname}的{tmdname}向您发送了异常卷阅卷任务。" ],
-  "scoring-mark_school": [ "普通阅卷任务通知", "{schoolname}的{tmdname}向您发送了普通卷阅卷任务。" ],
-  "scan-join_groupList": [ "扫码加入名单通知", "{tmdname}扫码加入名单,名单:{groupListName}" ], 
+  "transfer-admin_school": [ "管理员移交通知", "{tmdname}将{schoolName}的管理员移交给您。" ],
+  "scoring-arb_school": [ "仲裁卷阅卷任务通知", "{schoolName}的{tmdname}向您发送了仲裁卷阅卷任务。" ],
+  "scoring-err_school": [ "异常卷阅卷任务通知", "{schoolName}的{tmdname}向您发送了异常卷阅卷任务。" ],
+  "scoring-mark_school": [ "普通阅卷任务通知", "{schoolName}的{tmdname}向您发送了普通卷阅卷任务。" ],
+  "scan-join_groupList": [ "扫码加入名单通知", "{tmdname}扫码加入名单,名单:{groupListName}" ],
   "scan-join_school": [ "扫码加入学校通知", "{tmdname}扫码加入学校,学校名称:{schoolName}" ],
-  "submitanswer_homework": [ "作业提交通知", "{tmdname}已提交作业,作业名称({homeworkName})" ], 
-  "expire-school_lessonRecord": [ "课例到期通知", "您在{schoolname}的课例将在{expireTime}到期,课例名称:{lessonRecordName}" ], 
-  "expire-private_lessonRecord": [ "课例到期通知", "您的课例将在{expireTime}到期,课例名称:{lessonRecordName}" ] 
+  "submitanswer-school_homework": [ "作业提交通知", "{schoolName}的{tmdname}已提交作业,作业名称:{homeworkName}" ],
+  "submitanswer-private_homework": [ "作业提交通知", "{tmdname}已提交作业,作业名称({homeworkName})" ],
+  "expire-school_lessonRecord": [ "课例到期通知", "您在{schoolName}的课例将在{expireTime}到期,课例名称:{lessonName}" ],
+  "expire-private_lessonRecord": [ "课例到期通知", "您的课例将在{expireTime}到期,课例名称:{lessonName}" ]
 }

+ 19 - 17
TEAMModelOS.FunctionV4/Lang/zh-tw.json

@@ -1,18 +1,20 @@
-{
-  "request_school": [ "申请加入学校通知", "{tmdname}({tmdid})申请加入{schooName}。" ], 
-  "invite_school": [ "邀请加入学校通知", "{schooName}邀请您加入学校。" ], 
-  "remove_school": [ "从学校移除通知", "{schooName}将您从学校教师名单中移除。" ],  
-  "request-join_school": [ "同意申请加入学校通知", "{schooName}已同意您申请加入学校。" ],  
-  "invite-join_school": [ "同意邀请加入学校通知", "{tmdname}已接受加入{schooName}的邀请。" ],  
-  "coedit_syllabus": [ "邀请共编课纲通知", "{tmdname}邀请你参与共编校本课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ], 
-  "share_syllabus": [ "课纲分享接收通知", "{tmdname}向您分享了个人课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ], 
-  "transfer-admin_school": [ "管理员移交通知", "{tmdname}将{schooName}的管理员移交给您。" ],  
-  "scoring-arb_school": [ "仲裁卷阅卷任务通知", "{schoolname}的{tmdname}向您发送了仲裁卷阅卷任务。" ], 
-  "scoring-err_school": [ "异常卷阅卷任务通知", "{schoolname}的{tmdname}向您发送了异常卷阅卷任务。" ],  
-  "scoring-mark_school": [ "普通阅卷任务通知", "{schoolname}的{tmdname}向您发送了普通卷阅卷任务。" ],  
-  "scan-join_groupList": [ "扫码加入名单通知", "{tmdname}扫码加入名单,名单:{groupListName}" ],  
-  "scan-join_school": [ "扫码加入学校通知", "{tmdname}扫码加入学校,学校名称:{schoolName}" ],  
-  "submitanswer_homework": [ "作业提交通知", "{tmdname}已提交作业,作业名称({homeworkName})" ], 
-  "expire-school_lessonRecord": [ "课例到期通知", "您在{schoolname}的课例将在{expireTime}到期,课例名称:{lessonRecordName}" ],  
-  "expire-private_lessonRecord": [ "课例到期通知", "您的课例将在{expireTime}到期,课例名称:{lessonRecordName}" ]  
+{
+  "request_school": [ "申請加入學校通知", "{tmdname}({tmdid})申請加入{schoolName}。" ],
+  "invite_school": [ "邀請加入學校通知", "{schoolName}邀請您加入學校。" ],
+  "remove_school": [ "從學校移除通知", "{schoolName}將您從學校教師名單中移除。" ],
+  "request-join_school": [ "同意申請加入學校通知", "{schoolName}已同意您申請加入學校。" ],
+  "invite-join_school": [ "同意邀請加入學校通知", "{tmdname}已接受加入{schoolName}的邀請。" ],
+  "coedit_syllabus": [ "邀請共編課綱通知", "{schoolName}的{tmdname}邀請你參與共編校本課綱,冊別名稱:{volumeName},課綱節點名稱:{syllabusName}。" ],
+  "coedit_volume": [ "邀請共編冊別通知", "{schoolName}的{tmdname}邀請你參與共編校本冊別,冊別名稱:{volumeName}。" ],
+  "share_syllabus": [ "課綱分享接收通知", "{tmdname}向您分享了個人課綱,冊別名稱:{volumeName},課綱節點名稱:{syllabusName}。" ],
+  "transfer-admin_school": [ "管理員移交通知", "{tmdname}將{schoolName}的管理員移交給您。" ],
+  "scoring-arb_school": [ "仲裁卷閱卷任務通知", "{schoolName}的{tmdname}向您發送了仲裁卷閱卷任務。" ],
+  "scoring-err_school": [ "異常卷閱卷任務通知", "{schoolName}的{tmdname}向您發送了異常卷閱卷任務。" ],
+  "scoring-mark_school": [ "普通閱卷任務通知", "{schoolName}的{tmdname}向您發送了普通卷閱卷任務。" ],
+  "scan-join_groupList": [ "掃碼加入名單通知", "{tmdname}掃碼加入名單,名單:{groupListName}" ],
+  "scan-join_school": [ "掃碼加入學校通知", "{tmdname}掃碼加入學校,學校名稱:{schoolName}" ],
+  "submitanswer-school_homework": [ "作業提交通知", "{schoolName}的{tmdname}已提交作業,作業名稱:{homeworkName}" ],
+  "submitanswer-private_homework": [ "作業提交通知", "{tmdname}已提交作業,作業名稱({homeworkName})" ],
+  "expire-school_lessonRecord": [ "課例到期通知", "您在{schoolName}的課例將在{expireTime}到期,課例名稱:{lessonName}" ],
+  "expire-private_lessonRecord": [ "課例到期通知", "您的課例將在{expireTime}到期,課例名稱:{lessonName}" ]
 }

+ 5 - 3
TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs

@@ -31,6 +31,7 @@ using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
 using static TEAMModelOS.SDK.StatisticsService;
 using TEAMModelOS.SDK.DI.CoreAPI;
 using DocumentFormat.OpenXml.Office2010.Excel;
+using DocumentFormat.OpenXml.Wordprocessing;
 
 namespace TEAMModelOS.FunctionV4.ServiceBus
 {
@@ -1690,9 +1691,9 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                                     var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
                                                     var location = $"{Environment.GetEnvironmentVariable("Option:Location")}";
                                                     await _notificationService.SendNotification(clientID, clientSecret, location, url, notification); //站内发送消息
-                                                   
+                                                    string expireTime= DateTimeOffset.FromUnixTimeMilliseconds(lessonRecordExpire.expire).ToString("yyyy-MM-dd HH:mm:ss");
                                                     _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id = teacher.id, name = teacher.name, code = teacher.lang } }, "expire-private_lessonRecord", Constant.NotifyType_IES5_Course,
-                                                                 new Dictionary<string, object> { { "tmdname", teacher.name } }, $"{Environment.GetEnvironmentVariable("Option:Location")}", _configuration, _dingDing, "");
+                                                                 new Dictionary<string, object> { { "tmdname", teacher.name }, { "tmdid", teacher.name }, { "expireTime", expireTime }, { "lessonId", lessonRecordExpire.id }, { "lessonName", lessonRecordExpire. name } }, $"{Environment.GetEnvironmentVariable("Option:Location")}", _configuration, _dingDing, "");
                                                     var table = _azureStorage.GetCloudTableClient().GetTableReference("ChangeRecord");
                                                     List<ChangeRecord> records = await table.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", lessonRecordExpire.id } });
                                                     if (records.Count <= 0)
@@ -1856,8 +1857,9 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                 await _notificationService.SendNotification(clientID, clientSecret, location, url, notification); //站内发送消息
 
                 Teacher targetTeacher = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>($"{tmdid}", new PartitionKey($"Base"));
+                string expireTime = DateTimeOffset.FromUnixTimeMilliseconds(long.Parse($"{expire}")).ToString("yyyy-MM-dd HH:mm:ss");
                 _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id = targetTeacher.id, name = targetTeacher.name, code = targetTeacher.lang } }, "expire-private_lessonRecord", Constant.NotifyType_IES5_Course,
-                             new Dictionary<string, object> { { "tmdname", tmdname }  }, $"{Environment.GetEnvironmentVariable("Option:Location")}", _configuration, _dingDing, "");
+                             new Dictionary<string, object> { { "tmdname", tmdname }, { "tmdid",tmdid}, { "lessonId", id }, { "expireTime", expireTime }, { "lessonName",name } }, $"{Environment.GetEnvironmentVariable("Option:Location")}", _configuration, _dingDing, "");
             }
             catch (Exception ex)
             {

+ 5 - 0
TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj

@@ -18,6 +18,11 @@
 	<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
 		<DefineConstants>DEBUG;TRACE</DefineConstants>
 	</PropertyGroup>
+	<ItemGroup>
+	  <None Remove="Lang\en-us.json" />
+	  <None Remove="Lang\zh-cn.json" />
+	  <None Remove="Lang\zh-tw.json" />
+	</ItemGroup>
 	<ItemGroup>
 	  <Content Include="Lang\en-us.json">
 	    <CopyToOutputDirectory>Always</CopyToOutputDirectory>

+ 4 - 4
TEAMModelOS.SDK/Context/Constant/Constant.cs

@@ -23,10 +23,10 @@ namespace TEAMModelOS.SDK.DI
         public static readonly int private_lesson_expire = 7;
         public static readonly int school_lesson_expire = 7;
 
-        public static readonly string NotifyType_IES5_Management = "IES5_Management";
-        public static readonly string NotifyType_IES5_Course = "IES5_Course";
-        public static readonly string NotifyType_IES5_Task = "IES5_Task";
-        public static readonly string NotifyType_IES5_Contect = "IES5_Contect";
+        public static readonly string NotifyType_IES5_Management = "IES_Management";
+        public static readonly string NotifyType_IES5_Course = "IES_Course";
+        public static readonly string NotifyType_IES5_Task = "IES_Task";
+        public static readonly string NotifyType_IES5_Contect = "IES_Contect";
 
         public static readonly Dictionary<string, string> DefaultPeriod = new Dictionary<string, string> { 
             {"pre" ,"学前"},

+ 16 - 2
TEAMModelOS.SDK/DI/CoreAPI/CoreAPIHttpService.cs

@@ -134,6 +134,7 @@ namespace TEAMModelOS.SDK
                 var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
                 var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
                 var url = _configuration.GetValue<string>("HaBookAuth:CoreAPI");
+                string site = location;
                 if (location.Contains("China"))
                 {
                     location = "China";
@@ -142,6 +143,13 @@ namespace TEAMModelOS.SDK
                 {
                     location = "Global";
                 }
+                replaceData.Add("notifyCode", notifyCode);
+                replaceData.Add("location", site);
+                if (replaceData.ContainsKey("schoolId"))
+                {
+                    replaceData.Add("scope", "school");
+                }
+                else { replaceData.Add("scope", "private"); }
                 var token = CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location).Result;
                 _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}");
                 foreach (var group in groups)
@@ -152,13 +160,14 @@ namespace TEAMModelOS.SDK
                     if (JsonDocument.TryParseValue(ref reader, out JsonDocument jsonDoc) && jsonDoc.RootElement.TryGetProperty(notifyCode, out JsonElement json))
                     {
                         List<string> msgs = json.ToObject<List<string>>();
+                        
                         if (msgs.IsNotEmpty())
                         {
                             var tags = group.list.Select(x => $"{x.id}_{notifyType}");
                             NotifyData notifyData = new NotifyData
                             {
                                 hubName = "hita5",
-                                sender = "ies5",
+                                sender = "IES",
                                 tags = tags.ToList(),
                                 title = msgs[0],
                                 eventId = $"{notifyCode}-{_snowflakeId.NextId()}",
@@ -176,7 +185,12 @@ namespace TEAMModelOS.SDK
                                 });
                                 notifyData.body = msgs[1];
                             }
-                            _ = _httpClient.PostAsJsonAsync(url, notifyData);
+                           
+                            HttpResponseMessage responseMessage = _httpClient.PostAsJsonAsync($"{url}/service/PushNotify", notifyData).Result;
+                            if (responseMessage.StatusCode == HttpStatusCode.OK)
+                            {
+                                string content =   responseMessage.Content.ReadAsStringAsync().Result;
+                            }
                         }
                     }
                 }

+ 3 - 2
TEAMModelOS.SDK/Models/Service/LessonService.cs

@@ -636,10 +636,11 @@ namespace TEAMModelOS.SDK.Models.Service
                     var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
                     var location = $"{Environment.GetEnvironmentVariable("Option:Location")}";
                     await _notificationService.SendNotification(clientID, clientSecret, location, url, notification); //站内发送消息
-
+                    string expireTime = DateTimeOffset.FromUnixTimeMilliseconds(lessonRecord.expire).ToString("yyyy-MM-dd HH:mm:ss");
                     Teacher targetTeacher = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>($"{tmdid}", new PartitionKey($"Base"));
                     _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id = targetTeacher.id, name = targetTeacher.name, code = targetTeacher.lang } }, "expire-school_lessonRecord", Constant.NotifyType_IES5_Course,
-                                 new Dictionary<string, object> { { "tmdname", teacher.name }, { "schoolName", schoolBase.name } }, $"{Environment.GetEnvironmentVariable("Option:Location")}", _configuration, _dingDing, "");
+                                 new Dictionary<string, object> { { "tmdid", teacher.id }, { "tmdname", teacher.name }, { "schoolName", schoolBase.name }, 
+                                     { "schoolId", $"{school}" },{ "lessonId",lessonRecord.id }, { "expireTime", expireTime },{ "lessonName",lessonRecord.name } }, $"{Environment.GetEnvironmentVariable("Option:Location")}", _configuration, _dingDing, "");
                     var table = _azureStorage.GetCloudTableClient().GetTableReference("ChangeRecord");
                     List<ChangeRecord> records = await table.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", lessonRecord.id } });
                     if (records.Count <= 0)

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

@@ -3546,7 +3546,7 @@ const LANG_EN_US = {
         classroomAttr: 'Classroom Attribute',
         classroomCode: 'Classroom ID',
         classroomName: 'Classroom Name',
-        headmaster: 'Class Teacher',
+        headmaster: 'Class Teacher/Homeroom Teacher',
         setPeriod: "Select classroom's school system",
         setGrade: "Set classroom's grade",
         setHiteachCode: 'HiTeach Serial Number',
@@ -4111,10 +4111,10 @@ const LANG_EN_US = {
         sit1: 'id: Required. Student ID (4-12 digits number)',
         sit2: "pw: Optional. Password (if not entered, the default is the same as the student's student ID)",
         sit3: 'name: Required. Student Name',
-        sit4: 'stuYear: Required. Student enrollment year (usually the year he/she entered the school); e.g. 2022',
+        sit4: 'stuYear: Required. Student enrollment year (usually the year he/she entered the school), e.g. 2022',
         sit5: "className: Required. Student's Class, e.g., 101",
-        sit6: "classYear: Required. Usually the same as the enrolled year but depends on the student’s grade level e.g. 2020",
-        sit7: 'classId: Required. Class ID, e.g., 20200101',
+        sit6: "classYear: Required. Usually the same as the enrolled year but depends on the student’s grade level, for example, classYear will not be the same as the enrollment year if the student is retained. E.g. 2020.",
+        sit7: 'classId: Required. Class ID, e.g. 20200101',
         sit8: 'Incorrect ID format',
         sit9: 'Incorrect seat number format',
         sit10: 'Incorrect class ID format',

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

@@ -720,7 +720,7 @@ const LANG_ZH_TW = {
         generatOk: '生成成功',
         generateErr: '生成失敗',
         noStuTip: '未獲取到學生數據',
-        loadAll: '已加載完所有數據',
+        loadAll: '已載入所有數據',
         delete: '刪除',
         edit: '修改'
     },
@@ -2522,7 +2522,7 @@ const LANG_ZH_TW = {
             copyContent: '確認複製當前評量嗎?',
             copyContent1: '課中評量不能進行複製操作。',
             paperExam: '紙本測驗',
-            loadAll: '已載所有數據',
+            loadAll: '已載所有數據',
             crossSchool: '跨校評量,在當前學校無法查看發布對象'
         },
 

+ 10 - 10
TEAMModelOS/ClientApp/src/api/service.js

@@ -1,15 +1,15 @@
 import { fetch, post } from '@/api/http'
 export default {
-	/* 获取端外通知 */
-    getNotification: function (host,data) {
-        return post(`${host}/service/getnotification`, data)
+    /* 获取端外通知 */
+    getNotification: function (host, data) {
+        return post(`${host}/service/GetNotify`, data)
+    },
+    /* 删除通知 */
+    delNotification: function (host, data) {
+        return post(`${host}/service/DelNotify`, data)
     },
-	/* 删除通知 */
-	delNotification: function (host,data) {
-	    return post(`${host}/service/DelNotification`, data)
-	},
     /* 获取id详细信息 */
-    getIdProfile: function (host,data) {
+    getIdProfile: function (host, data) {
         return post(`${host}/oauth2/profile`, data)
     },
     /* 发送短信验证码 */
@@ -20,11 +20,11 @@ export default {
         return post(`/core/sendsms/pin`, data)
     },
     /* 发送邮件验证码 */
-    sandMailCode: function (host,data) {
+    sandMailCode: function (host, data) {
         return post(`${host}/service/sandmail/pin`, data)
     },
     /* 裝置或服務取得金鑰及刷新金鑰 */
-    getToken: function (host,data) {
+    getToken: function (host, data) {
         return post(`${host}/oauth2/token`, data)
     },
 }

+ 52 - 12
TEAMModelOS/ClientApp/src/common/BaseNotification.vue

@@ -18,11 +18,11 @@
             <Icon type="md-close" color="#ababab" size="20" @click.stop="doDeleteMsg(item,index)" />
           </span>
           <p class="item-name">
-            <Icon type="ios-checkmark-circle" color="#17ac5a" size="18" style="margin-right: 5px;" />{{ getMsgType(item) }}
+            <Icon type="ios-checkmark-circle" color="#17ac5a" size="18" style="margin-right: 5px;" />{{ item.title }}
           </p>
           <p class="item-content">
-            <span>{{ getMsgContent(item) }}</span>
-            <span class="item-time" :title="$tools.formatTime(item.body.time)">{{ getMsgTime(item) }}</span>
+            <span>{{ item.content }}</span>
+            <span class="item-time" :title="$tools.formatTime(item.ts * 1000)">{{ getMsgTime(item) }}</span>
           </p>
         </div>
       </div>
@@ -91,7 +91,7 @@ export default {
     },
     /* 获取消息通知时间 */
     getMsgTime(msg) {
-      return this.$tools.getDateDiff(msg.body.time)
+      return this.$tools.getDateDiff(msg.ts * 1000)
     },
     /* 获取消息通知内容 */
     getMsgContent(msg) {
@@ -172,7 +172,16 @@ export default {
             name: "syllabus",
             params: {
               tabName: 'fromCreate',
-              id: body.vid
+              id: body.volumeId
+            }
+          }
+          break;
+        case 'coedit_volume':
+          routerInfo = {
+            name: "syllabus",
+            params: {
+              tabName: 'fromCreate',
+              id: body.volumeId
             }
           }
           break;
@@ -196,7 +205,7 @@ export default {
             name: "personalSyllabus",
             params: {
               tabName: 'fromShare',
-              id: body.vid
+              id: body.volumeId
             }
           }
           break;
@@ -215,7 +224,27 @@ export default {
             name: "manageHomeWork",
             params: {
               ac: {
-                id: body.sid
+                id: body.homeworkId
+              }
+            }
+          }
+          break;
+        case 'submitanswer-school_homework':
+          routerInfo = {
+            name: "manageHomeWork",
+            params: {
+              ac: {
+                id: body.homeworkId
+              }
+            }
+          }
+          break;
+        case 'submitanswer-private_homework':
+          routerInfo = {
+            name: "manageHomeWork",
+            params: {
+              ac: {
+                id: body.homeworkId
               }
             }
           }
@@ -225,10 +254,20 @@ export default {
             name: "course",
           }
           break;
+        case 'expire-school_lessonRecord':
+          routerInfo = {
+            name: "course",
+          }
+          break;
+        case 'expire-private_lessonRecord':
+          routerInfo = {
+            name: "course",
+          }
+          break;
         default:
           break;
       }
-      this.changeSchool(body.schoolcode, routerInfo)
+      this.changeSchool(body.schoolId, routerInfo)
       this.isOpen = false
     },
     /* 删除单条消息 */
@@ -295,7 +334,7 @@ export default {
         let srvAdr = this.$store.state.config.srvAdr
         let host = srvAdr == 'Global' ? this.$store.state.config.Global.coreAPIUrl : this.$store.state.config.China.coreAPIUrl
         await this.$api.service.delNotification(host, {
-          "from": from,
+          // "from": from,
           "receiver": this.$store.state.userInfo.TEAMModelId,
           "indexNums": idArr
         })
@@ -314,9 +353,10 @@ export default {
         } else {
           // 只查询当前站点的消息通知
           let curLocation = localStorage.getItem('location')
-          this.msgArr = localMsgs.filter(i => {
-            return i.body.location === curLocation
-          })
+          this.msgArr = localMsgs
+          // this.msgArr = localMsgs.filter(i => {
+          //   return i.body.location === curLocation
+          // })
         }
       }
     },

+ 31 - 3
TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/Exam.vue

@@ -6,9 +6,18 @@
             {{ $t("studentWeb.courseContent.noExam") }}
         </div>
         <div v-else class="exam-chart-wrap">
-            <ExamTable :examDetaiInfo="examDetaiInfo" :examInfo="examInfo" :recordInfo="recordInfo"></ExamTable>
             <ScoreBarChart :total="classTotal" :subjectNames="subjectName"></ScoreBarChart>
-            <ExamQu :quData="correctData[0] ? correctData[0].data : []"></ExamQu>
+            <!-- <ExamTable :examDetaiInfo="examDetaiInfo" :examInfo="examInfo" :recordInfo="recordInfo"></ExamTable> -->
+            <!-- <ExamQu :quData="correctData[0] ? correctData[0].data : []"></ExamQu>s -->
+        </div>
+        <div style="width: 105px; text-align: center; margin-right: 5px;">
+            <p style="font-size: 18px; font-weight: bold; margin-top: 10px;">{{ getScore }}</p>
+            <!-- 查看更多 -->
+            <div class="data-count-item view-more" @click="toEvDetail" style="width: 100%;">
+                <p class="data-text" style="color:#2d8cf0">
+                    {{ $t("totalAnalysis.more") }}
+                </p>
+            </div>
         </div>
         <div>
             <Icon type="ios-person" class="owner-student-client-icon"/>
@@ -46,7 +55,8 @@ export default {
             examDetaiInfo: undefined,
             paperQuInfo: [],
             correctData: [],
-            subjectName: []
+            subjectName: [],
+            getScore: 0,
         }
     },
     methods: {
@@ -62,6 +72,11 @@ export default {
                 }
                 this.$api.studentWeb.FindStudentPaper(req).then(res => {
                     this.examDetaiInfo = res
+                    res.stuScore[0].forEach((item, index) => {
+                        if(item != -1) {
+                            this.getScore += item
+                        }
+                    })
                     res.subjects.forEach(item => {
                         this.subjectName.push(item.name)
                     })
@@ -147,6 +162,19 @@ export default {
                 }
             })
         },
+        toEvDetail() {
+            this.$router.push({
+                path: "/studentWeb/examView",
+                query: {aId: this.examInfo.ExamId}
+            })
+            /* this.$router.push({
+                path: '/home/evDetail',
+                query: {
+                    examId: this.examInfo.id,
+                    code: `Exam-${this.$store.state.userInfo.TEAMModelId}`
+                }
+            })  */ 
+        },
     },
     computed: {
         examScore() {

+ 27 - 3
TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/ExamQu.vue

@@ -99,7 +99,32 @@ export default {
                                 }
                             },
                             axisLabel: {
-                                rotate: 0
+                                rotate: 0,
+                                /* formatter: (params) => {
+                                    return  `${params}\n${_this.quData[params-1].type ? '{typea|√}' : '{typeb|×}'}`
+                                },
+                                rich: {
+                                    typea: {
+                                        color: '#00AD6C',
+                                        fontSize: 20,
+                                        // height: 24,
+                                        // padding: [0, 5, 0, 5],
+                                        align: 'center'
+                                    },
+                                    typeb: {
+                                        color: '#FF5508',
+                                        fontSize: 20,
+                                        // height: 24,
+                                        // padding: [0, 5, 0, 5],
+                                        align: 'center'
+                                    },
+                                    count: {
+                                        color: '#333',
+                                        height: 24,
+                                        // padding: [0, 5, 0, 5],
+                                        // align: 'right'
+                                    },
+                                }, */
                             }
                         },
                         yAxis: {
@@ -127,7 +152,6 @@ export default {
                                         // } else {
                                         //     return params.data
                                         // }
-                                        // console.log(params);
                                         // 统计正确率的算法
                                         return _this.isShowRate ? `${params.data.type ? '{typea|√}' : '{typeb|×}'}\n{count|${params.data.value.toFixed(0)}%}` : ''
                                     },
@@ -265,7 +289,7 @@ export default {
 <style scoped lang="less">
 .qu-score {
     padding: 15px 20px 0 20px;
-    width: 500px;
+    width: 440px;
     height: 250px;
 }
 .qu-score-count {

+ 171 - 0
TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/PopQues.vue

@@ -0,0 +1,171 @@
+<template>
+    <div class="pop-ques-wrap">
+        <div v-if="quType != 'complete'">
+            <TeacherClient></TeacherClient>
+            <p class="event-type">
+                {{evtType == 'PopQuesLoad' ? $t('studentWeb.hiteachNote.qA') : $t('studentWeb.hiteachNote.qaAgain')}}
+                <Tooltip :content="$t('talMgmt.text47')">
+                <v-icon class="qu-flip-icon" :style="{'color':isOverview ? '':'#2d8cf0'}" :iconClass="imgSrc" v-show="quType === 'single' || quType === 'multiple' || quType === 'judge'" @click.native="isOverview = !isOverview" />
+                </Tooltip>
+            </p>
+            <!-- 统计数据 -->
+            <template v-if="isOverview">
+                <!-- 单选、多选、判断选项分布 -->
+                <OptionCount v-if="quType === 'single' || quType === 'multiple' || quType === 'judge'" :optionCount="optionData" :answer="answer"></OptionCount>
+                <!-- 填空题(文字题) -->
+                <!-- <CompleteAns v-else-if="quType === 'complete'" :answer="answerData" :students="students"></CompleteAns> -->
+                <!-- 如果有设置正确答案的正确率统计 -->
+                <CorrectRate :correctData="correctData" v-if="hasAnswer"></CorrectRate>
+            </template>
+            <div v-else>
+                <p v-for="key in Object.keys(optionData)" :key="key">
+                    <Tag :color="key == 'noAns' ? 'warning' : 'primary'">
+                        {{key == 'noAns' ? $t('cusMgt.rcd.noAns') : key}}
+                    </Tag>
+                    <Tag color="default" v-for="s in optionData[key]" :key="s">
+                        {{s}}
+                    </Tag>
+                </p>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+import TeacherClient from '@/view/classrecord/eventchart/TeacherClient.vue'
+import CorrectRate from '@/view/classrecord/eventchart/CorrectRate.vue'
+import OptionCount from '@/view/classrecord/eventchart/OptionCount.vue'
+import CompleteAns from '@/view/classrecord/eventchart/CompleteAns.vue'
+export default {
+    props: {
+        irsData: {
+            type: Object,
+            default: () => {
+                return {}
+            }
+        },
+        evtType: {
+            type: String,
+            default: 'PopQuesLoad'
+        },
+        students: {
+            type: Array,
+            default: () => {
+                return []
+            }
+        }
+    },
+    data() {
+        require('@/icons/svg/flop.svg')
+        return {
+            imgSrc: 'flop',
+            isOverview: true,
+            answerData: [],
+            hasAnswer: false,
+            quType: '',
+            optionData: {},
+            correctData: {},
+            answer: [],//正确答案
+            optionMap: {
+                0: [],
+                1: ['A'],
+                2: ['A', 'B'],
+                3: ['A', 'B', 'C'],
+                4: ['A', 'B', 'C', 'D'],
+                5: ['A', 'B', 'C', 'D', 'E'],
+                6: ['A', 'B', 'C', 'D', 'E', 'F'],
+                7: ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
+                9: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'],
+                9: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
+            }
+        }
+    },
+    components: {
+        OptionCount, CorrectRate, TeacherClient, CompleteAns
+    },
+    watch: {
+        irsData: {
+            deep: true,
+            immediate: true,
+            handler(n, o) {
+                console.log(n)
+                if (n.clientAnswers && n.question) {
+                    this.hasAnswer = !!n.question.exercise?.answer?.length
+                    // let noAns = 0 //未作答
+                    let noAns = [] //未作答
+                    // let opts = n.question?.exercise?.opts || 0 //opts不准确,需要实际去item
+                    let opts = n.question?.item[0]?.option?.length || 0
+                    this.answer = n.question?.exercise?.answer || []
+                    this.quType = n.question?.exercise?.type || ''
+                    this.optionData = {}
+                    this.correctData = {
+                        wrong: 0,
+                        right: 0
+                    }
+                    this.optionMap[opts].forEach(o => {
+                        // this.optionData[o] = 0
+                        this.optionData[o] = []
+                    })
+                    this.answerData = []
+                    // 首次作答
+                    if (this.evtType === 'PopQuesLoad') {
+                        this.answerData = this._.cloneDeep(n.clientAnswers[0])
+                    }
+                    //二次作答
+                    else if (this.evtType === 'ReAtmpAnsStrt') {
+                        this.answerData = this._.cloneDeep(n.clientAnswers[1])
+                    }
+                    //客观题
+                    if (this.quType === 'single' || this.quType === 'multiple' || this.quType === 'judge') {
+                        if (this.answerData.length) {
+                            this.answerData.forEach((stu, index) => {
+                                //选项分布
+                                if (stu.length) {
+                                    stu.forEach(a => {
+                                        // if (!this.optionData[a]) this.optionData[a] = 0
+                                        // this.optionData[a]++
+                                        if (!this.optionData[a]) this.optionData[a] = []
+                                        this.optionData[a].push(this.students[index]?.name)
+                                    })
+                                } else {
+                                    // noAns++
+                                    noAns.push(this.students[index]?.name)
+                                }
+
+                                // 正确率
+                                let stuCopy = JSON.parse(JSON.stringify(stu))
+                                let ansCopy = JSON.parse(JSON.stringify(this.answer)) //处理触发无限更新
+                                if (stuCopy.sort().toString() == ansCopy.sort().toString()) {
+                                    this.correctData.right++
+                                } else {
+                                    this.correctData.wrong++
+                                }
+
+                            })
+                        }
+                    }
+                    // if (noAns) this.optionData['noAns'] = noAns
+                    if (noAns.length) this.optionData['noAns'] = noAns
+                    console.log('选项数据', this.optionData)
+                }
+            }
+        }
+    }
+}
+</script>
+<style lang="less" scoped>
+.qu-flip-icon {
+    cursor: pointer;
+    width: 25px;
+    height: 25px;
+    transform: scale(0.7);
+    vertical-align: middle;
+}
+.pop-ques-wrap {
+    display: flex;
+}
+.event-type {
+    margin-right: 20px;
+    font-size: 15px;
+    font-weight: 600;
+}
+</style>

+ 32 - 0
TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/RecordView.less

@@ -168,6 +168,7 @@
                         margin-right: 0;
                         width: 130px;
                         cursor: pointer;
+                        border: 2px solid #cecece;
                     }
     
                     .messagetoPPT-tag {
@@ -450,6 +451,36 @@
             .course-cur-img {
                 height: 100%;
             }
+            
+            .custom-page-change {
+                position: absolute;
+                top: 50%;
+                margin-top: -20px;
+                background: rgba(60, 60, 60, 0.6);
+                color: white;
+                width: 35px;
+                height: 35px;
+                text-align: center;
+                line-height: 35px;
+                font-size: 20px;
+                cursor: pointer;
+                border-radius: 50%;
+                display: none;
+            }
+
+            &:hover {
+                .custom-page-change {
+                    display: block;
+                }
+            }
+
+            .custom-prev {
+                left: 10px;
+            }
+
+            .custom-next {
+                right: 10px;
+            }
         }
 
         .page-wrap {
@@ -492,6 +523,7 @@
                     overflow: hidden;
                     position: relative;
                     margin-top: 10px;
+                    background: #f9f9f9;
             
                     .no-interaction {
                         height: 100%;

+ 24 - 6
TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/RecordView.vue

@@ -101,6 +101,12 @@
                                 </div>
                                 <div class="courseware-wrap">
                                     <!-- <DrawHTEX :mapJson="mapJson"></DrawHTEX> -->
+                                    <div class="custom-page-change custom-prev" @click="changePage('prev')">
+                                        <Icon type="ios-arrow-back" />
+                                    </div>
+                                    <div class="custom-page-change custom-next" @click="changePage('next')">
+                                        <Icon type="ios-arrow-forward" />
+                                    </div>
                                     <img :src="curImg" alt="" class="course-cur-img">
                                     <div class="page-wrap">
                                         <Page :total="pageList.length" :current="curPage" :page-size="1" size="small" @on-change="getCurHTEX" />
@@ -123,10 +129,10 @@
                                 </div>
                                 <div>
                                     <Button type="warning" @click="filterFn('all')">{{ $t("cusMgt.rcd.filter1") }}</Button>
-                                    <Button type="warning" :disabled="!filtertype.push" @click="filterFn('push')">{{ $t("cusMgt.rcd.filter2") }}({{ filtertype.push }})</Button>
-                                    <Button type="warning" :disabled="!filtertype.task" @click="filterFn('task')">{{ $t("cusMgt.rcd.filter3") }}({{ filtertype.task }})</Button>
-                                    <Button type="warning" :disabled="!filtertype.irs" @click="filterFn('irs')">{{ $t("cusMgt.rcd.filter4") }}({{ filtertype.irs }})</Button>
-                                    <Button type="warning" :disabled="!filtertype.exam" @click="filterFn('exam')">{{ $t("cusMgt.rcd.filter5") }}({{ filtertype.exam }})</Button>
+                                    <Button type="warning" :disabled="!filtertype.push" @click="filterFn('push')">{{ $t("cusMgt.rcd.filter2") }}<!-- ({{ filtertype.push }}) --></Button>
+                                    <Button type="warning" :disabled="!filtertype.task" @click="filterFn('task')">{{ $t("cusMgt.rcd.filter3") }}<!-- ({{ filtertype.task }}) --></Button>
+                                    <Button type="warning" :disabled="!filtertype.irs" @click="filterFn('irs')">{{ $t("cusMgt.rcd.filter4") }}<!-- ({{ filtertype.irs }}) --></Button>
+                                    <Button type="warning" :disabled="!filtertype.exam" @click="filterFn('exam')">{{ $t("cusMgt.rcd.filter5") }}<!-- ({{ filtertype.exam }}) --></Button>
                                 </div>
                             </div>
                         </div>
@@ -203,7 +209,7 @@ import RcdPoster from '../../../view/homepage/RcdPoster.vue';
 import Loading from '@/common/Loading.vue';
 import DataCount from './newDataCount.vue';
 import ShowQues from './ShowQues.vue';
-import PopQues from '@/view/classrecord/eventchart/PopQues.vue';
+import PopQues from './PopQues.vue';
 import Buzr from './Buzr.vue';
 import Push from '@/view/classrecord/eventchart/Push.vue';
 import StuReceive from './StuReceive.vue';
@@ -332,7 +338,7 @@ export default {
                 doubleGreen: false,
                 quality: false,
                 DESC: "startTime",
-                pageCount: 10, //返回六条数据(分页)
+                pageCount: 100, //返回六条数据(分页)
                 today: false,
                 continuationToken: this.continuationToken, //返回的有值的话,下次查询就要用这个值
                 groupIds: [this.courseNow.list],
@@ -735,6 +741,14 @@ export default {
                 this.player.currentTime(pageInfo.time)
             }
         },
+        // 自定义换页功能
+        changePage(type) {
+            if (type == 'prev') {
+                if (this.curPage > 1) this.curPage--
+            } else if (type == 'next') {
+                if (this.curPage < this.pageList.length) this.curPage++
+            }
+        },
         // 点击课件page
         getCurHTEX(page) {
             this.curPage = page
@@ -897,6 +911,10 @@ export default {
         background-color: #FEE49E;
         border-color: #FEE49E;
     }
+
+    .tea-push-img {
+        border: 2px solid #cecece;
+    }
 }
 
 .owner-student-client-icon {

+ 4 - 4
TEAMModelOS/ClientApp/src/components/student-web/ClassRecord/ScoreBarChart.vue

@@ -152,10 +152,10 @@ export default {
 
 <style scoped>
 .score-bar-chart {
-    width: 300px;
+    width: 440px;
     /* margin: auto; */
     /* margin-bottom: 50px; */
-    padding: 15px 40px 0px 40px;
+    padding: 15px 20px 0 20px;
     height: 270px;
     color: rgba(0, 0, 0, 0.726);
 }
@@ -186,8 +186,8 @@ export default {
 }
 
 .score-stu {
-    width: 306px;
-    height: 250px;
+    width: 100%;
+    height: 100%;
 }
 
 @media screen and (max-width: 1365px) {

+ 25 - 4
TEAMModelOS/ClientApp/src/utils/public.js

@@ -1240,14 +1240,35 @@ export default {
 		const cache = {};
 		const promises = [];
 
+		function getBase64ImageUrl(url) {
+			return new Promise((r, j) => {
+				var img = new Image();
+				img.src = url;
+				img.crossOrigin = "anonymous";
+				img.onload = function () {
+					var canvas = document.createElement("canvas");
+					canvas.width = img.width
+					canvas.height = img.height
+					var ctx = canvas.getContext("2d");
+					ctx.drawImage(img, 0, 0, img.width, img.height);
+					var ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
+					var dataURL = canvas.toDataURL("image/" + ext);
+					r(dataURL);
+				}
+			})
+		}
+
 		/* 循环下载所有文件后 加入promise队列 */
 		await urls.forEach(item => {
-			const promiseItem = this.getFile(item).then(dta => {
+			const promiseItem = this.getFile(item).then(async dta => {
 				const arr_name = item.split("/"); //处理名称
 				var file_name = arr_name[arr_name.length - 1].split('?')[0];
-				zip.file(file_name, dta, {
-					binary: true
-				}); // 逐个添加文件
+				// 需要判断是否为图片类型 如果是图片则需要通过base64的方式去进行打包
+				let isImg = ['jpg', 'jpeg', 'png'].includes(file_name.split('.')[file_name.split('.').length - 1].toLowerCase())
+				let isJson = ['json'].includes(file_name.split('.')[file_name.split('.').length - 1].toLowerCase())
+				let imgBase64 = isImg ? await getBase64ImageUrl(item) : ''
+				let encodeConfig = isJson ? {} : isImg ? { base64: true } : { binary: true }
+				zip.file(file_name, isImg ? imgBase64.replace(/^data:image\/(png|jpg|jpeg);base64,/, '') : dta, encodeConfig); // 逐个添加文件
 				cache[file_name] = dta;
 			});
 			promises.push(promiseItem);

+ 16 - 5
TEAMModelOS/ClientApp/src/view/Home.vue

@@ -240,12 +240,18 @@ export default {
       this.curPlatform = goPlatform
     },
     async getAllNotice(user_profile, userId) {
-      let schoolNotice = await this.getSchoolNotice(user_profile, userId)
+      // let schoolNotice = await this.getSchoolNotice(user_profile, userId)
       let privateNotice = await this.getPrivateNotice(userId)
-      this.msgs = schoolNotice.concat(privateNotice).reverse()
+      // this.msgs = schoolNotice.concat(privateNotice).reverse()
+      console.error(privateNotice)
+      this.msgs = privateNotice
       if (this.msgs.length) {
         this.msgs.forEach(i => {
-          i.body = JSON.parse(this.getBodyJson(i.body))
+          i.content = i.body
+          i.indexNum = i.index
+          i.body = JSON.parse(this.getBodyJson(i.data)).value
+          i.label = i.body.notifyCode
+
         })
       }
       localStorage.setItem('msgs', JSON.stringify(this.msgs))
@@ -281,10 +287,15 @@ export default {
         let host = srvAdr == 'Global' ? this.$store.state.config.Global.coreAPIUrl : this.$store.state
           .config.China.coreAPIUrl
         this.$api.service.getNotification(host, {
-          "from": "ies5:" + this.location + ":private",
+          "sender": [],
           "receiver": userId
         }).then(res => {
-          r(res.msgs)
+          if (res.length) {
+            let needMsgs = res.filter(msg => msg.data && JSON.parse(this.getBodyJson(msg.data)).value.scope)
+            r(needMsgs)
+          } else {
+            r([])
+          }
         })
       })
     },

+ 236 - 219
TEAMModelOS/ClientApp/src/view/areaMgmt/AreaBase.vue

@@ -1,284 +1,301 @@
 <template>
-    <div id="main">
-        <Loading v-if="isLoading" :top="300"></Loading>
-        <AreaLayout>
-            <!-- 头部右侧个人中心部分 -->
-            <div class="header-right-box fl-around" slot="header-content">
-                <Icon style="display:block" custom="iconfont icon-home" :color="routerName == 'homePage' ? '#1CC0F3':'#d0d0d0'" @click="toHome" :title="$t('system.goHome')"/>
-				<Icon type="md-open" @click="changePlatform" :title="$t('system.changePlat')" v-if="hasArea"/>
-                <BaseNotification :msgs="msgs"></BaseNotification>
-                <span class="header-split"></span>
-                <BaseUserPoptip @logout="basicMenu('quit')"></BaseUserPoptip>
-            </div>
-            <div id="areaContent" class="custom-scroll-bar" slot="content">
-                <router-view v-if="!$route.meta.isKeep" :key="this.$route.name"></router-view>
-                <keep-alive>
-                    <router-view v-if="$route.meta.isKeep" :key="this.$route.name"></router-view>
-                </keep-alive>
-            </div>
-        </AreaLayout>
-    </div>
+  <div id="main">
+    <Loading v-if="isLoading" :top="300"></Loading>
+    <AreaLayout>
+      <!-- 头部右侧个人中心部分 -->
+      <div class="header-right-box fl-around" slot="header-content">
+        <Icon style="display:block" custom="iconfont icon-home" :color="routerName == 'homePage' ? '#1CC0F3':'#d0d0d0'" @click="toHome" :title="$t('system.goHome')" />
+        <Icon type="md-open" @click="changePlatform" :title="$t('system.changePlat')" v-if="hasArea" />
+        <BaseNotification :msgs="msgs"></BaseNotification>
+        <span class="header-split"></span>
+        <BaseUserPoptip @logout="basicMenu('quit')"></BaseUserPoptip>
+      </div>
+      <div id="areaContent" class="custom-scroll-bar" slot="content">
+        <router-view v-if="!$route.meta.isKeep" :key="this.$route.name"></router-view>
+        <keep-alive>
+          <router-view v-if="$route.meta.isKeep" :key="this.$route.name"></router-view>
+        </keep-alive>
+      </div>
+    </AreaLayout>
+  </div>
 </template>
 
 <script>
 import AreaLayout from './AreaLayout.vue'
 export default {
-    name: 'headers',
-    props: ['parentToChild', 'identityselect'],
-    components: {
-        AreaLayout
+  name: 'headers',
+  props: ['parentToChild', 'identityselect'],
+  components: {
+    AreaLayout
+  },
+  data() {
+    return {
+      msgs: [],
+      isShowMock: false,
+      isOpenDrawer: false,
+      routerName: '',
+      isLoading: false
+    }
+  },
+  created() {
+    this.$Message.config({
+      duration: 3
+    });
+    // 检查超时操作页面,清空缓存数据
+    let webEndTime = localStorage.getItem('webEndTime')
+    let time_now = new Date().getTime()
+    if (webEndTime && time_now > webEndTime) {
+      console.log('长时间未操作,清空storage,重新登录')
+      this.loginOut()
+    }
+    this.$store.dispatch('user/checkSchoolCode');// 設定登入成功的學校簡碼
+    this.$store.dispatch('user/checkUserProfile');// 檢查使用者個人詳細資訊
+    this.$store.dispatch('user/checkStudentProfile');// 檢查學生的詳細資訊
+
+
+    let user = JSON.parse(decodeURIComponent(sessionStorage.userInfo, "utf-8"))
+    let user_profile = JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8"))
+    console.log(user_profile)
+    if (user_profile.schools) {
+      user_profile.schools = user_profile.schools.filter((item) => {
+        return item.status == 'join'
+      })
+    } else {
+      user_profile.schools = []
+    }
+    if (user_profile.schools.length) {
+      this.$store.commit('setUserInfo', {
+        TEAMModelId: user.id || user.sub,
+        name: user.name,
+        schoolCode: user_profile.defaultschool || user_profile.schools[0].schoolId
+      })
+    } else {
+      this.$store.commit('setUserInfo', {
+        TEAMModelId: user.id || user.sub,
+        name: user.name,
+        schoolCode: this.$GLOBAL.DEFAULT_SCHOOL_CODE
+      })
+    }
+    this.$store.commit('setPrivateSpace', user_profile.total || 0)
+    this.getAllNotice(user_profile, user.id)
+    this.curPlatform = localStorage.getItem('platform') || 'school'
+
+  },
+  methods: {
+    loginOut() {
+      let login_schoolCode = localStorage.getItem('login_schoolCode')
+      let srvAdr = localStorage.getItem('srvAdr')
+      let versionFlag = localStorage.getItem('versionFlag')
+      localStorage.clear()
+      localStorage.setItem('srvAdr', srvAdr)
+      localStorage.setItem('versionFlag', versionFlag)
+      localStorage.setItem('login_schoolCode', login_schoolCode)
+      window.location.href = window.location.origin + '/login'
     },
-    data() {
-        return {
-            msgs: [],
-            isShowMock: false,
-            isOpenDrawer: false,
-            routerName: '',
-            isLoading: false
-        }
+    changePlatform() {
+      let goPlatform = this.curPlatform === 'area' ? 'school' : 'area'
+      let homePath = 'home'
+      this.$router.push({
+        name: goPlatform === 'area' ? 'area' : homePath
+      })
+      localStorage.setItem('platform', this.curPlatform === 'area' ? 'school' : 'area')
+      this.curPlatform = goPlatform
     },
-    created() {
-		this.$Message.config({
-		    duration: 3
-		});
-		// 检查超时操作页面,清空缓存数据
-		let webEndTime = localStorage.getItem('webEndTime')
-		let time_now = new Date().getTime()
-		if (webEndTime && time_now > webEndTime) {
-		    console.log('长时间未操作,清空storage,重新登录')
-		    this.loginOut()
-		}
-		this.$store.dispatch('user/checkSchoolCode');// 設定登入成功的學校簡碼
-		this.$store.dispatch('user/checkUserProfile');// 檢查使用者個人詳細資訊
-		this.$store.dispatch('user/checkStudentProfile');// 檢查學生的詳細資訊
-		
-		
-        let user = JSON.parse(decodeURIComponent(sessionStorage.userInfo, "utf-8"))
-        let user_profile = JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8"))
-        console.log(user_profile)
-        if (user_profile.schools) {
-            user_profile.schools = user_profile.schools.filter((item) => {
-                return item.status == 'join'
-            })
-        } else {
-            user_profile.schools = []
-        }
-        if (user_profile.schools.length) {
-            this.$store.commit('setUserInfo', {
-                TEAMModelId: user.id || user.sub,
-                name: user.name,
-                schoolCode: user_profile.defaultschool || user_profile.schools[0].schoolId
-            })
-        } else {
-            this.$store.commit('setUserInfo', {
-                TEAMModelId: user.id || user.sub,
-                name: user.name,
-                schoolCode: this.$GLOBAL.DEFAULT_SCHOOL_CODE
-            })
-        }
-        this.$store.commit('setPrivateSpace', user_profile.total || 0)
-        this.getAllNotice(user_profile, user.id)
-		this.curPlatform = localStorage.getItem('platform') || 'school'
+    async getAllNotice(user_profile, userId) {
+      // let schoolNotice = await this.getSchoolNotice(user_profile, userId)
+      let privateNotice = await this.getPrivateNotice(userId)
+      // this.msgs = schoolNotice.concat(privateNotice).reverse()
+      console.error(privateNotice)
+      this.msgs = privateNotice
+      if (this.msgs.length) {
+        this.msgs.forEach(i => {
+          i.content = i.body
+          i.body = JSON.parse(this.getBodyJson(i.data)).value
+          i.label = i.body.notifyCode
 
+        })
+      }
+      localStorage.setItem('msgs', JSON.stringify(this.msgs))
+      console.log('端外通知', this.msgs)
     },
-    methods: {
-        loginOut() {
-            let login_schoolCode = localStorage.getItem('login_schoolCode')
-            let srvAdr = localStorage.getItem('srvAdr')
-            let versionFlag = localStorage.getItem('versionFlag')
-            localStorage.clear()
-            localStorage.setItem('srvAdr', srvAdr)
-            localStorage.setItem('versionFlag', versionFlag)
-            localStorage.setItem('login_schoolCode', login_schoolCode)
-            window.location.href = window.location.origin + '/login'
-        },
-		changePlatform(){
-			let goPlatform = this.curPlatform === 'area' ? 'school' : 'area'
-            let homePath = 'home'
-			this.$router.push({
-			    name: goPlatform === 'area' ? 'area' : homePath
-			})
-			localStorage.setItem('platform',this.curPlatform === 'area' ? 'school' : 'area')
-			this.curPlatform = goPlatform
-		},
-        async getAllNotice(user_profile, userId) {
-            let schoolNotice = await this.getSchoolNotice(user_profile, userId)
-            let privateNotice = await this.getPrivateNotice(userId)
-            this.msgs = schoolNotice.concat(privateNotice)
-            console.log('端外通知', this.msgs)
-        },
-        getSchoolNotice(user_profile, userId) {
-            return new Promise((r, j) => {
-                if (this.hasSchool) {
-					let srvAdr = this.$store.state.config.srvAdr
-					let host = srvAdr == 'Global' ? this.$store.state.config.Global.coreAPIUrl : this.$store.state.config.China.coreAPIUrl
-                    this.$api.service.getNotification(host,{
-                        "from": "ies5:" + (user_profile.defaultschool || user_profile.schools[0].schoolId),
-                        "receiver": userId
-                    }).then(res => {
-                        r(res.msgs)
-                    })
-                } else {
-                    r([])
-                }
-            })
-        },
-        getPrivateNotice(userId) {
-            return new Promise((r, j) => {
-				let srvAdr = this.$store.state.config.srvAdr
-				let host = srvAdr == 'Global' ? this.$store.state.config.Global.coreAPIUrl : this.$store.state.config.China.coreAPIUrl
-                this.$api.service.getNotification(host,{
-                    "from": "ies5:private",
-                    "receiver": userId
-                }).then(res => {
-                    r(res.msgs)
-                })
-            })
-        },
-        toHome() {
-            this.$router.push({ path: '/area/areaMgmt' })
-        },
-        toSettings() {
-            this.$router.push({ path: '/home/settings' })
-        },
-        toFeedback() {
-            this.$router.push({ path: '/home/feedback' })
-        },
-        closeMenu() {
-            this.isOpenDrawer = false
-        },
-        basicMenu(name) {
-            if (name == 'quit') {
-                this.$store.commit('user/resetSchoolProfile')
-                this.$store.commit('user/resetTeachers')
-                this.$store.commit('student/setStudents',[])
-                this.$User.logout()
-                this.$router.push({
-                    path: '/login'
-                })
-            }
+    getSchoolNotice(user_profile, userId) {
+      return new Promise((r, j) => {
+        if (this.hasSchool) {
+          let srvAdr = this.$store.state.config.srvAdr
+          let host = srvAdr == 'Global' ? this.$store.state.config.Global.coreAPIUrl : this.$store.state.config.China.coreAPIUrl
+          this.$api.service.getNotification(host, {
+            "from": "ies5:" + (user_profile.defaultschool || user_profile.schools[0].schoolId),
+            "receiver": userId
+          }).then(res => {
+            r(res.msgs)
+          })
+        } else {
+          r([])
         }
+      })
+    },
+    getPrivateNotice(userId) {
+      return new Promise((r, j) => {
+        let srvAdr = this.$store.state.config.srvAdr
+        let host = srvAdr == 'Global' ? this.$store.state.config.Global.coreAPIUrl : this.$store.state
+          .config.China.coreAPIUrl
+        this.$api.service.getNotification(host, {
+          "sender": [],
+          "receiver": userId
+        }).then(res => {
+          if (res.length) {
+            let needMsgs = res.filter(msg => msg.data && JSON.parse(this.getBodyJson(msg.data)).value.scope)
+            r(needMsgs)
+          } else {
+            r([])
+          }
+        })
+      })
+    },
+    toHome() {
+      this.$router.push({ path: '/area/areaMgmt' })
+    },
+    toSettings() {
+      this.$router.push({ path: '/home/settings' })
+    },
+    toFeedback() {
+      this.$router.push({ path: '/home/feedback' })
     },
-    mounted() {
+    closeMenu() {
+      this.isOpenDrawer = false
+    },
+    basicMenu(name) {
+      if (name == 'quit') {
+        this.$store.commit('user/resetSchoolProfile')
+        this.$store.commit('user/resetTeachers')
+        this.$store.commit('student/setStudents', [])
+        this.$User.logout()
+        this.$router.push({
+          path: '/login'
+        })
+      }
+    }
+  },
+  mounted() {
 
-        if (localStorage.getItem('noSave') && JSON.parse(localStorage.getItem('noSave')).length) {
-            this.$tools.deleteNoSave(JSON.parse(localStorage.getItem('noSave')))
-        } else {
-            localStorage.setItem('noSave', '[]')
-        }
+    if (localStorage.getItem('noSave') && JSON.parse(localStorage.getItem('noSave')).length) {
+      this.$tools.deleteNoSave(JSON.parse(localStorage.getItem('noSave')))
+    } else {
+      localStorage.setItem('noSave', '[]')
+    }
 
-        this.$EventBus.$off('onGlobalLoading')
-        this.$EventBus.$on('onGlobalLoading', val => {
-            this.isLoading = val
-        })
+    this.$EventBus.$off('onGlobalLoading')
+    this.$EventBus.$on('onGlobalLoading', val => {
+      this.isLoading = val
+    })
 
-        this.$EventBus.$off('noSave')
-        this.$EventBus.$on('noSave', val => {
-            let curNoSaveArr = JSON.parse(localStorage.getItem('noSave'))
-            curNoSaveArr.push(val)
-            localStorage.setItem('noSave', JSON.stringify(curNoSaveArr))
-        })
+    this.$EventBus.$off('noSave')
+    this.$EventBus.$on('noSave', val => {
+      let curNoSaveArr = JSON.parse(localStorage.getItem('noSave'))
+      curNoSaveArr.push(val)
+      localStorage.setItem('noSave', JSON.stringify(curNoSaveArr))
+    })
 
+  },
+  computed: {
+    hasSchool() {
+      return this.$store.state.userInfo.hasSchool;
     },
-    computed: {
-        hasSchool() {
-            return this.$store.state.userInfo.hasSchool;
-        },
-		hasArea(){
-			return this.$store.state.user.userProfile.areas.length > 0
-		}
-    },
-    watch: {
-        $route: {
-            handler(val, oldval) {
-                this.routerName = val.name
-            },
-            // 深度观察监听
-            deep: true,
-            //立即执行
-            immediate: true
-        }
+    hasArea() {
+      return this.$store.state.user.userProfile.areas.length > 0
+    }
+  },
+  watch: {
+    $route: {
+      handler(val, oldval) {
+        this.routerName = val.name
+      },
+      // 深度观察监听
+      deep: true,
+      //立即执行
+      immediate: true
     }
+  }
 }
 </script>
 
 <style scoped>
 .header-split {
-    display: block;
-    width: 0;
-    background: #636363;
-    height: 25px;
-	margin: 0 15px;
+  display: block;
+  width: 0;
+  background: #636363;
+  height: 25px;
+  margin: 0 15px;
 }
 .header-right-box {
-    margin: 12px;
-    line-height: 1.5;
-    float: right;
-    height: 25px;
-    margin-right: 20px;
+  margin: 12px;
+  line-height: 1.5;
+  float: right;
+  height: 25px;
+  margin-right: 20px;
 }
 
 .header-right-box .ivu-icon {
-    font-size: 20px;
-	margin-right: 20px;
-    color: #d0d0d0;
-    cursor: pointer;
+  font-size: 20px;
+  margin-right: 20px;
+  color: #d0d0d0;
+  cursor: pointer;
 }
 
 .header-right-box img {
-    width: 40px;
-    border-radius: 50%;
-    border: 2px solid #595959;
+  width: 40px;
+  border-radius: 50%;
+  border: 2px solid #595959;
 }
 
 .fl-around {
-    display: flex;
-    align-items: center;
-    justify-content: space-around;
+  display: flex;
+  align-items: center;
+  justify-content: space-around;
 }
 </style>
 
 <style>
 html,
 body {
-    height: 100%;
-    width: 100%;
-    margin: 0px;
-    padding: 0px;
+  height: 100%;
+  width: 100%;
+  margin: 0px;
+  padding: 0px;
 }
 
 #main {
-    width: 100%;
-    height: 100%;
+  width: 100%;
+  height: 100%;
 }
 
 #main .layout {
-    border: none;
-    border-radius: 0px;
+  border: none;
+  border-radius: 0px;
 }
 
 #areaContent {
-    height: 100%;
-    /* background: #242328; */
-    /* overflow: hidden; */
+  height: 100%;
+  /* background: #242328; */
+  /* overflow: hidden; */
 }
 
 /*重绘滚动条样式*/
 .scrollstyle::-webkit-scrollbar {
-    width: 5px;
+  width: 5px;
 }
 
 .ivu-drawer-body::-webkit-scrollbar-track {
-    display: none;
+  display: none;
 }
 
 .scrollstyle::-webkit-scrollbar-thumb {
-    border-radius: 10px;
-    background: #94998a;
+  border-radius: 10px;
+  background: #94998a;
 }
 
 .scrollstyle::-webkit-scrollbar-button {
-    display: none;
+  display: none;
 }
 </style>
 

+ 91 - 2
TEAMModelOS/ClientApp/src/view/art/AreaArtSetting.vue

@@ -33,10 +33,33 @@
           </Collapse>
         </div>
       </div>
+      <div class="setting-block">
+        <p class="title">考核指标分数占比设置</p>
+        <div class="content art-setting-wrap">
+          <el-tree :data="quotas" :props="defaultProps" class="tree" node-key="id" ref="tree">
+            <span class="custom-tree-node" slot-scope="{ node, data }">
+              <span>【{{ node.level }} 级】</span>
+              <span>{{ data.name }}</span>
+              <span style="color:red;margin-left:10px">占比 {{ data.percent }}%</span>
+              <Icon type="md-create" size="16" style="margin-left:10px" color="#ccc" @click.stop="onNodeClick(node,data)"></Icon>
+            </span>
+          </el-tree>
+        </div>
+      </div>
     </div>
     <Modal v-model="addArtDimensionModal" :title="isEditDimensional ? '编辑艺术维度' : '添加艺术维度'" footer-hide width="700px">
       <BaseDimensionForm :dimension="dimensionInfo" v-if="addArtDimensionModal" @onFinish="onDimensionEditFinish"></BaseDimensionForm>
     </Modal>
+    <Modal v-model="setRateModal" :title="'设置指标分数占比'" width="700px">
+      <div v-for="item in rateArr">
+        <span>{{ item.name }}</span>
+        <Slider v-model="item.percent" :min="0" :max="100" show-input></Slider>
+      </div>
+      <div slot="footer">
+        <Button type="text" @click="setRateModal = false">取消</Button>
+        <Button type="primary" @click="confirmSetRate">确定</Button>
+      </div>
+    </Modal>
   </div>
 </template>
 
@@ -48,6 +71,12 @@ export default {
   },
   data() {
     return {
+      setRateModal: false,
+      defaultProps: {
+        children: 'children',
+        label: 'name'
+      },
+      rateArr: [],
       addArtDimensionModal: false,
       openCustom: false,
       isEditDimensional: false,
@@ -56,14 +85,46 @@ export default {
       addDimensionModal: false,
       btnLoading: false,
       artDimensions: [],
-      dimensionInfo: null
+      dimensionInfo: null,
+      quotas: []
     }
   },
   created() {
     this.getAreaSetting()
-
   },
   methods: {
+    /* 节点点击事件 */
+    onNodeClick(node) {
+      if (node.level === 1) {
+        this.rateArr = this.quotas
+      } else {
+        this.rateArr = node.parent.data.children
+      }
+      this.setRateModal = true
+    },
+    /* 确认保存占比调整 */
+    confirmSetRate() {
+      let sum = this.rateArr.map(i => i.percent).reduce((a, b) => a + b, 0)
+      if (sum !== 100) {
+        this.$Message.warning('请保证100%占比合理分配!')
+        return false
+      }
+      this.setRateModal = false
+      this.$api.areaArt.upsertArtSetting({
+        opt: 'UpsertQuota',
+        areaId: sessionStorage.getItem('areaId'),
+        quotas: this.quotas
+      }).then(res => {
+        if (!res.error) {
+          this.$Message.success('操作成功')
+        } else {
+          this.$Message.error('Fail')
+        }
+      }).catch(e => {
+        this.$Message.error('Fail')
+      })
+
+    },
     /* 获取当前区级设置数据 */
     getAreaSetting() {
       this.$api.areaArt.findArtSetting({
@@ -72,6 +133,7 @@ export default {
         if (res.setting) {
           console.log(res)
           this.artDimensions = res.setting.dimensions
+          this.quotas = res.setting.quotas
           //   this.artDimensions.forEach(i => {
           //     console.log(i.type)
           //     i.type = i.type.map(j => this.$GLOBAL.ART_PERIOD_TYPES[j])
@@ -171,6 +233,33 @@ export default {
   display: flex;
   flex-direction: column;
 
+  .el-tree {
+    width: 50%;
+  }
+
+  .el-tree--highlight-current
+    .el-tree-node.is-current
+    > .el-tree-node__content {
+    background-color: var(--active-item-start) !important;
+  }
+  .el-tree-node__content {
+    height: 40px;
+    &:hover {
+      height: 40px;
+    }
+
+    .el-tree-node__expand-icon {
+      padding: 4px 6px;
+    }
+  }
+  .el-tree__empty-block {
+    display: none;
+  }
+
+  .custom-tree-node {
+    justify-content: flex-start;
+  }
+
   .setting-block {
     position: relative;
     padding: 10px 20px;

+ 3 - 4
TEAMModelOS/Controllers/Both/GroupListController.cs

@@ -26,7 +26,6 @@ using Microsoft.Extensions.Hosting;
 using OpenXmlPowerTools;
 using TEAMModelOS.SDK.Models.Dtos;
 using Microsoft.AspNetCore.Hosting;
-using DocumentFormat.OpenXml.Wordprocessing;
 
 namespace TEAMModelOS.Controllers
 {
@@ -186,8 +185,8 @@ namespace TEAMModelOS.Controllers
                     {
                         idNameCodes.Add(item);
                     }
-                    _coreAPIHttpService.PushNotify(idNameCodes, $"{code}_school", Constant.NotifyType_IES5_Course,
-                              new Dictionary<string, object> { { "tmdname", name }, { "groupListName", data.stuList.name } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                    _coreAPIHttpService.PushNotify(idNameCodes, $"scan-join_groupList", Constant.NotifyType_IES5_Course,
+                              new Dictionary<string, object> { { "tmdid", id }, { "tmdname", name }, { "groupListName", data.stuList.name }, { "groupListId", data.stuList.id } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
                 }
                 return Ok(new { data.stuList, data.status });
             }
@@ -279,7 +278,7 @@ namespace TEAMModelOS.Controllers
                         idNameCodes.Add(item);
                     }
                     _coreAPIHttpService.PushNotify(idNameCodes, $"{code}_school", Constant.NotifyType_IES5_Course,
-                              new Dictionary<string, object> { { "tmdname", _name }, { "groupListName", data.stuList.name } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                              new Dictionary<string, object> { { "tmdid",userid },{ "tmdname", _name }, { "groupListName", data.stuList.name } , { "groupListId", data.stuList.id } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
                 }
                 return Ok(new { data.stuList, data.status });
             }

+ 10 - 6
TEAMModelOS/Controllers/Both/ShareController.cs

@@ -181,10 +181,14 @@ namespace TEAMModelOS.Controllers
                                     var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
                                     var location = _option.Location;
                                     var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification);
-                                    Teacher targetTeacher = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>($"{tmdid}", new PartitionKey($"Base"));
-                                    _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id= targetTeacher .id,name= targetTeacher .name,code= targetTeacher .lang} }, $"{x.type}_syllabus", Constant.NotifyType_IES5_Task,
-                                                 new Dictionary<string, object> { { "tmdname", x.issuerName }, { "volumeName", x.volumeName }, { "syllabusName", x.syllabusName } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
-                              
+                                    if (x.type.Equals("coedit")) {
+                                        School school = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(request.school, new Azure.Cosmos.PartitionKey("Base"));
+                                        Teacher targetTeacher = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>($"{tmdid}", new PartitionKey($"Base"));
+                                        _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id = targetTeacher.id, name = targetTeacher.name, code = targetTeacher.lang } }, $"{x.type}_syllabus", Constant.NotifyType_IES5_Contect,
+                                                     new Dictionary<string, object> {
+                                                         { "tmdname", x.issuerName }, { "tmdid", x.issuer }, { "schoolId",school.id}, { "schoolName",school.name},{ "volumeId", x.volumeId }, { "syllabusId", x.id }, { "volumeName", x.volumeName }, { "syllabusName", x.syllabusName } }
+                                                     , _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                                    }
                                 }
                                 await client.GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync<Syllabus>(syllabus, new PartitionKey($"Syllabus-{request.school}"));
                             }
@@ -277,8 +281,8 @@ namespace TEAMModelOS.Controllers
                                     var location = _option.Location;
                                     var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification);
                                     Teacher targetTeacher = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>($"{tmdid}", new PartitionKey($"Base"));
-                                    _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id = targetTeacher.id, name = targetTeacher.name, code = targetTeacher.lang } }, $"{x.type}_syllabus", Constant.NotifyType_IES5_Task,
-                                                 new Dictionary<string, object> { { "tmdname", x.issuerName }, { "volumeName", x.volumeName }, { "syllabusName", x.syllabusName } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                                    _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id = targetTeacher.id, name = targetTeacher.name, code = targetTeacher.lang } }, $"{x.type}_syllabus", Constant.NotifyType_IES5_Contect,
+                                                 new Dictionary<string, object> { { "tmdname", x.issuerName } , { "tmdid", x.issuer },  { "volumeId", x.volumeId }, { "syllabusId", x.id }, { "volumeName", x.volumeName }, { "syllabusName", x.syllabusName } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
 
                                 }
                                 await client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync<Syllabus>(syllabusD, new PartitionKey($"Syllabus-{request.issuer}"));

+ 34 - 4
TEAMModelOS/Controllers/Both/VolumeController.cs

@@ -19,6 +19,11 @@ using TEAMModelOS.SDK.Models.Cosmos.Common;
 using HTEXLib.COMM.Helpers;
 using Microsoft.AspNetCore.Authorization;
 using TEAMModelOS.Filter;
+using Microsoft.Extensions.Hosting;
+using OpenXmlPowerTools;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using TEAMModelOS.SDK.Models.Dtos;
 
 namespace TEAMModelOS.Controllers
 {
@@ -33,13 +38,18 @@ namespace TEAMModelOS.Controllers
         private readonly SnowflakeId _snowflakeId;
         private readonly DingDing _dingDing;
         private readonly Option _option;
-
-        public VolumeController(AzureCosmosFactory azureCosmos, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option)
+        private readonly CoreAPIHttpService _coreAPIHttpService;
+        private readonly IWebHostEnvironment _environment;
+        private readonly IConfiguration _configuration;
+        public VolumeController(IConfiguration configuration, CoreAPIHttpService coreAPIHttpServic, IWebHostEnvironment environment, AzureCosmosFactory azureCosmos, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option)
         {
             _azureCosmos = azureCosmos;
             _snowflakeId = snowflakeId;
             _dingDing = dingDing;
-            _option = option?.Value; ;
+            _option = option?.Value; 
+            _environment = environment;
+            _coreAPIHttpService = coreAPIHttpServic;
+            _configuration = configuration;
         }
         /*
         {
@@ -272,7 +282,7 @@ namespace TEAMModelOS.Controllers
             request.ttl = -1;
             request.code = "Volume-" + request.code;
             // 检查册别条件相同的是否存在
-            
+            List<string> coeditIds = new List<string>();
             string code = "Volume-";
             if (request.scope.Equals("private"))
             {
@@ -290,6 +300,11 @@ namespace TEAMModelOS.Controllers
                 try {
                     if (request.scope.Equals("school"))
                     {
+                        Volume volume=  await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<Volume>(request.id, new Azure.Cosmos.PartitionKey(request.code));
+                        var exceptIds= volume.auth.Select(x => x.tmdid).Except(request.auth.Select(y => y.tmdid));
+                        if (exceptIds.Any()) {
+                            coeditIds.AddRange(exceptIds);
+                        }
                         await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<Volume>(request, request.id, new Azure.Cosmos.PartitionKey(request.code));
                     }
                     else if (request.scope.Equals("private")) {
@@ -350,6 +365,7 @@ namespace TEAMModelOS.Controllers
                         await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync(request, new PartitionKey(request.code));
                     }
                     else {
+                        coeditIds = request.auth.Select(x => x.tmdid).ToList() ;
                         await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync(request, new PartitionKey(request.code));
                     }
                 }
@@ -377,6 +393,20 @@ namespace TEAMModelOS.Controllers
             //        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync(share, new PartitionKey($"{share.code}"));
             //    }
             //}
+
+            if (coeditIds.IsNotEmpty()) {
+                School school = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>(request.school, new Azure.Cosmos.PartitionKey("Base"));
+                string sql = $"select c.id, c.name ,c.lang as code from c where c.id in ({string.Join(",", coeditIds.Select(x => $"'{x}'"))})";
+                List<IdNameCode> idNameCodes = new List<IdNameCode>();
+                await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher)
+                    .GetItemQueryIterator<IdNameCode>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base") }))
+                {
+                    idNameCodes.Add(item);
+                }
+                _coreAPIHttpService.PushNotify(idNameCodes, "coedit_volume", Constant.NotifyType_IES5_Contect,
+               new Dictionary<string, object> { { "tmdname", request.creatorName }, { "tmdid", request.creatorId },{ "schoolName",school.name }, { "schoolId",school.id }, { "volumeId", request.id }, { "volumeName", request.name } },
+               _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+            }
             return Ok(request);
         }
     }

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

@@ -1,5 +1,6 @@
 using Azure.Cosmos;
 using Azure.Storage.Blobs.Models;
+using DocumentFormat.OpenXml.Spreadsheet;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.Http;
@@ -229,7 +230,7 @@ namespace TEAMModelOS.Controllers.Client
                 idNameCodes.Add(item);
             }
             _coreAPIHttpService.PushNotify(idNameCodes, $"{bizcode}_school", Constant.NotifyType_IES5_Management,
-                      new Dictionary<string, object> { { "tmdname", name }, { "schooName", schoolInfo.name } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                      new Dictionary<string, object> { { "tmdname", teacher.name }, { "schoolName", schoolInfo.name }, { "schoolId", $"{school}" }, { "tmdid", teacher.id } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
             return Ok(new { schoolTeacher.roles, schoolTeacher.status, school = $"{school}", schoolInfo.name, schoolInfo.picture });
         }
 

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

@@ -25,6 +25,7 @@ using Microsoft.AspNetCore.Authorization;
 using System.Net.Http;
 using TEAMModelOS.SDK.DI.CoreAPI;
 using Microsoft.AspNetCore.Hosting;
+using static TEAMModelOS.SDK.SchoolService;
 
 namespace TEAMModelOS.Controllers
 {
@@ -2939,7 +2940,7 @@ namespace TEAMModelOS.Controllers
                                             idNameCodes.Add(idNameCode);
                                         }
                                         _coreAPIHttpService.PushNotify(idNameCodes, $"{bizcode}_school", Constant.NotifyType_IES5_Task,
-                                                  new Dictionary<string, object> { { "tmdname", name }, { "schooName", schname } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                                                  new Dictionary<string, object> { { "tmdname", name }, { "schoolName", schname }, { "schoolId", $"{school}" }, { "tmdid", userid } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
                                         return Ok(new { msg = "需要仲裁", code = 2 });
                                     }
                                     if (item.scores.Count > 0)
@@ -3104,7 +3105,7 @@ namespace TEAMModelOS.Controllers
                     idNameCodes.Add(item);
                 }
                 _coreAPIHttpService.PushNotify(idNameCodes, $"{bizcode}_school", Constant.NotifyType_IES5_Task,
-                          new Dictionary<string, object> { { "tmdname", name }, { "schooName", schname } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                          new Dictionary<string, object> { { "tmdname", name }, { "schoolName", schname }, { "schoolId", $"{school}" }, { "tmdid", userid } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
                 /* scoring.type = 2;
                  scoring.err = err.GetString();*/
             }

+ 16 - 3
TEAMModelOS/Controllers/Common/HomeworkController.cs

@@ -26,6 +26,8 @@ using HTEXLib.COMM.Helpers;
 using Microsoft.AspNetCore.Authorization;
 using TEAMModelOS.SDK.DI.CoreAPI;
 using Microsoft.AspNetCore.Hosting;
+using Azure.Storage.Blobs.Models;
+using static TEAMModelOS.SDK.SchoolService;
 
 namespace TEAMModelOS.Controllers.Learn
 {
@@ -807,9 +809,20 @@ namespace TEAMModelOS.Controllers.Learn
                                     var location = _option.Location;
                                     var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification);
                                   Teacher teacherData= await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>(homework.creatorId, new PartitionKey("Base"));
-                                    _coreAPIHttpService.PushNotify(new List<IdNameCode> { 
-                                        new IdNameCode { id = teacherData.id,name=teacherData.name,code=teacherData.lang} }, "submitanswer_homework", Constant.NotifyType_IES5_Course,
-                               new Dictionary<string, object> { { "tmdname", name }, { "homeworkName", homework.name } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                                    if (!string.IsNullOrWhiteSpace(homework.school))
+                                    {
+                                        School schoolData = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(school, new PartitionKey("Base"));
+                                        _coreAPIHttpService.PushNotify(new List<IdNameCode> {
+                                        new IdNameCode { id = teacherData.id,name=teacherData.name,code=teacherData.lang} }, "submitanswer-school_homework", Constant.NotifyType_IES5_Course,
+                                   new Dictionary<string, object> { { "tmdname", name }, { "schoolName", schoolData.name }, { "schoolId", $"{school}" }, { "tmdid", userid }, { "homeworkId", homework.id }, { "homeworkName", homework.name } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                                    }
+                                    else {
+                                        _coreAPIHttpService.PushNotify(new List<IdNameCode> {
+                                        new IdNameCode { id = teacherData.id,name=teacherData.name,code=teacherData.lang} }, "submitanswer-private_homework", Constant.NotifyType_IES5_Course,
+                                       new Dictionary<string, object> { { "tmdname", name },  { "tmdid", userid }, { "homeworkId", homework.id }, { "homeworkName", homework.name } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                                    }
+                                   
+                                   
                                 }
                                 //TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO 写入方便教师查看的作答记录
                                 try

+ 2 - 1
TEAMModelOS/Controllers/School/CorrectController.cs

@@ -30,6 +30,7 @@ using TEAMModelOS.SDK.DI.CoreAPI;
 using TEAMModelOS.SDK.Models.Dtos;
 using Microsoft.Extensions.Hosting;
 using Microsoft.AspNetCore.Hosting;
+using DocumentFormat.OpenXml.Office2010.Excel;
 
 namespace TEAMModelOS.Controllers
 {
@@ -260,7 +261,7 @@ namespace TEAMModelOS.Controllers
                     idNameCodes.Add(item);
                 }
                 _coreAPIHttpService.PushNotify(idNameCodes, $"{bizcode}_school", Constant.NotifyType_IES5_Task,
-                                 new Dictionary<string, object> { { "tmdname", name }, { "schooName", schname } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                                 new Dictionary<string, object> { { "tmdname", name }, { "schoolName", schname }, { "schoolId", $"{school}" }, { "tmdid", userid } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
                 return Ok(new { vote = request });
             }
             catch (Exception e)

+ 4 - 2
TEAMModelOS/Controllers/School/SchoolController.cs

@@ -30,6 +30,8 @@ using TEAMModelOS.SDK.DI.CoreAPI;
 using Azure.Storage.Blobs.Models;
 using Microsoft.Extensions.Hosting;
 using Microsoft.AspNetCore.Hosting;
+using DocumentFormat.OpenXml.Office2010.Excel;
+using TEAMModelOS.SDK.Models.Service;
 
 namespace TEAMModelOS.Controllers
 {
@@ -1808,8 +1810,8 @@ namespace TEAMModelOS.Controllers
                         var location = _option.Location;
                         var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification);
 
-                        _coreAPIHttpService.PushNotify(inviteids, $"remove_school", Constant.NotifyType_IES5_Management,
-                                     new Dictionary<string, object> { { "tmdname", adminName }, { "schooName", schoolBase.name } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                        _coreAPIHttpService.PushNotify(inviteids, $"{bizcode}_school", Constant.NotifyType_IES5_Management,
+                        new Dictionary<string, object> { { "tmdname", adminName }, { "schoolName", schoolBase.name }, { "schoolId", $"{_schoolId}" }, { "tmdid", adminId } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
                     }
                     break;
             }

+ 17 - 4
TEAMModelOS/Controllers/School/SchoolTeacherController.cs

@@ -26,6 +26,7 @@ using DocumentFormat.OpenXml.Wordprocessing;
 using static TEAMModelOS.Controllers.FixDataController;
 using Microsoft.Extensions.Hosting;
 using Microsoft.AspNetCore.Hosting;
+using DocumentFormat.OpenXml.Office2010.Excel;
 
 namespace TEAMModelOS.Controllers
 {
@@ -747,7 +748,7 @@ namespace TEAMModelOS.Controllers
                 var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification);
 
                 _coreAPIHttpService.PushNotify(ids, $"{bizcode}_school", Constant.NotifyType_IES5_Management,
-                                 new Dictionary<string, object> { { "tmdname", tname }, { "schooName", schname } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                                 new Dictionary<string, object> { { "tmdname", tname }, { "schoolName", schname }, { "schoolId", $"{school_code}" } , { "tmdid",tid} }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
                 return Ok(new { exist = keys });
             }
             catch (Exception ex)
@@ -917,7 +918,7 @@ namespace TEAMModelOS.Controllers
                 var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification); 
 
                 _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id = teacher.id, name=teacher.name, code= teacher.lang} }, $"{bizcode}_school", Constant.NotifyType_IES5_Management,
-                                 new Dictionary<string, object> { { "tmdname", tname }, { "schooName", schname } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                                 new Dictionary<string, object> { { "tmdname", tname }, { "schoolName", schname }, { "schoolId", $"{school_code}" },   { "tmdid", tid } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
                 return Ok(new { });
             }
             catch (Exception ex)
@@ -974,6 +975,16 @@ namespace TEAMModelOS.Controllers
                         }
                     }
                     Teacher teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>(id.ToString(), new PartitionKey("Base"));
+                    //教师还未加入,就被移除,则不通知。
+                    bool needNotify = false;
+                    var sc= teacher.schools.FindAll(x => x.schoolId.Equals($"{school_code}"));
+                    if (sc.IsNotEmpty()) {
+                        sc.ForEach(z => {
+                            if (z.status.Equals("join")) {
+                                needNotify = true;
+                            }
+                        });
+                    }
                     var school = teacher.schools.RemoveAll(x => x.schoolId.Equals(school_code.GetString(), StringComparison.OrdinalIgnoreCase));
                     if (!string.IsNullOrEmpty(teacher.defaultSchool) && teacher.defaultSchool.Equals($"{school_code}"))
                     {
@@ -1032,9 +1043,11 @@ namespace TEAMModelOS.Controllers
                     var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
                     var location = _option.Location;
                     var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification);
+                    if (needNotify) {
+                        _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id = teacher.id, name = teacher.name, code = teacher.lang } }, $"remove_school", Constant.NotifyType_IES5_Management,
+                                     new Dictionary<string, object> { { "tmdname", tname }, { "schoolName", schname }, { "schoolId", $"{school_code}" }, { "tmdid", tid } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
 
-                    _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id = teacher.id, name = teacher.name, code = teacher.lang } }, $"remove_school", Constant.NotifyType_IES5_Management,
-                                     new Dictionary<string, object> { { "tmdname", tname }, { "schooName", schname } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                    }
                 }
                 return Ok(new { });
             }

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

@@ -32,6 +32,7 @@ using System.Text;
 using Microsoft.Azure.Cosmos.Table;
 using TEAMModelOS.SDK.DI.CoreAPI;
 using Microsoft.AspNetCore.Hosting;
+using DocumentFormat.OpenXml.Office2010.Excel;
 
 namespace TEAMModelOS.Controllers
 {
@@ -270,7 +271,7 @@ namespace TEAMModelOS.Controllers
                                 }
                                 Teacher targetTeacher = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>($"{_targetTecher}", new PartitionKey($"Base"));
                                 _coreAPIHttpService.PushNotify(new List<IdNameCode> { new IdNameCode { id= targetTeacher.id,name= targetTeacher.name,code=targetTeacher.lang} }, "transfer-admin_school", Constant.NotifyType_IES5_Management,
-                                    new Dictionary<string, object> { { "tmdname", name },{ "schooName", schoolBase.name } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
+                                    new Dictionary<string, object> { { "tmdname", name },{ "schoolName", schoolBase.name }, { "schoolId", $"{school}" } , { "tmdid", userid } }, _option.Location, _configuration, _dingDing, _environment.ContentRootPath);
                                 _ = _azureStorage.SaveLog("transfer-admin-role", new { request, userid, name, school, schoolName = schoolBase.name, targetTecher = _targetTecher, }.ToJsonString(), bizId: $"{userid}-{schoolBase.id}-{_targetTecher}", httpContext: HttpContext, dingDing: _dingDing, scope: "school");
                                 return Ok(new { status = 1 });
                             }
@@ -1182,7 +1183,7 @@ namespace TEAMModelOS.Controllers
                             idNameCodes.Add(item);
                         }
                         _coreAPIHttpService.PushNotify(idNameCodes, $"{code}_school", Constant.NotifyType_IES5_Management,
-                                  new Dictionary<string, object> { { "tmdname", name }, { "schooName", schoolBase.name } }, _option.Location,_configuration,_dingDing, _environment.ContentRootPath) ;
+                                  new Dictionary<string, object> {{ "tmdname", name }, { "schoolName", schoolBase.name }, { "schoolId",$"{school_code}" },{ "tmdid",id} }, _option.Location,_configuration,_dingDing, _environment.ContentRootPath) ;
                     }
                     return Ok(new { stauts = 1 });
                 }

+ 19 - 17
TEAMModelOS/Lang/en-us.json

@@ -1,18 +1,20 @@
-{
-  "request_school": [ "Apply to join school", "{tmdname}({tmdid}) applying to join {schooName}." ],  
-  "invite_school": [ "Invite to join school", "{schooName} has invited you to join." ], 
-  "remove_school": [ "Remove from school", "{schooName} removed you from the school's teacher list." ],  
-  "request-join_school": [ "Agree to join school", "{schooName} has agreed you to join the school." ], 
-  "invite-join_school": [ "Accepting join school invitation", "{tmdname} has accepted an invitation to join {schooName}." ], 
-  "coedit_syllabus": [ "Invite to co-edit syllabus", "{tmdname} invites you to co-edit school-based syllabus, Volume name: {volumeName}, Node name: {syllabusName}." ],  
-  "share_syllabus": [ "Receive shared syllabus", "{tmdname} shared personal syllabus with you, Volume name: {volumeName}, Node name: {syllabusName}." ],  
-  "transfer-admin_school": [ "Transfer administrator", "{tmdname} will transfer the administrator of {schooName} to you." ],  
-  "scoring-arb_school": [ "Assign arbitration exam scoring task", "{tmdname} of {schoolname} has assign you an arbitration exam scoring task." ],  
-  "scoring-err_school": [ "Assign abnormal exam paper grading task", "{tmdname} of {schoolname} has assign you an abnormal exam paper grading task." ],  
-  "scoring-mark_school": [ "Assign exam paper grading task", "{tmdname} of {schoolname} has assign you an exam paper grading task." ],  
-  "scan-join_groupList": [ "Join course notice", "{tmdname} join the {groupListName} course via QRcode scanning" ], 
-  "scan-join_school": [ "Join school notice", "{tmdname} join school, {schoolName}, via QRcode scanning" ],  
-  "submitanswer_homework": [ "Homework submission notice", "{tmdname} has submitted a homework({homeworkName})" ],  
-  "expire-school_lessonRecord": [ "Lesson record expiration notice", "Your lesson record, {lessonRecordName}, on {schoolname} will expire at {expireTime}" ],  
-  "expire-private_lessonRecord": [ "Lesson record expiration notice", "Your lesson record, {lessonRecordName} will expire at {expireTime}" ]  
+{
+  "request_school": [ "Apply to join school", "{tmdname}({tmdid}) applying to join {schoolName}." ],
+  "invite_school": [ "Invite to join school", "{schoolName} has invited you to join." ],
+  "remove_school": [ "Remove from school", "{schoolName} removed you from the school's teacher list." ],
+  "request-join_school": [ "Agree to join school", "{schoolName} has agreed you to join the school." ],
+  "invite-join_school": [ "Accepting join school invitation", "{tmdname} has accepted an invitation to join {schoolName}." ],
+  "coedit_syllabus": [ "Invite to co-edit syllabus", "{tmdname} of {schoolName} has invited you to co-edit school-based syllabus, Volume name: {volumeName}, Node name: {syllabusName}." ],
+  "coedit_volume": [ "Invite to co-edit volume", "{tmdname} of {schoolName} has invited  you to co-edit school-based volume,Volume name:{volumeName}." ],
+  "share_syllabus": [ "Receive shared syllabus", "{tmdname} shared personal syllabus with you, Volume name: {volumeName}, Node name: {syllabusName}." ],
+  "transfer-admin_school": [ "Transfer administrator", "{tmdname} will transfer the administrator of {schoolName} to you." ],
+  "scoring-arb_school": [ "Assign arbitration exam scoring task", "{tmdname} of {schoolName} has assign you an arbitration exam scoring task." ],
+  "scoring-err_school": [ "Assign abnormal exam paper grading task", "{tmdname} of {schoolName} has assign you an abnormal exam paper grading task." ],
+  "scoring-mark_school": [ "Assign exam paper grading task", "{tmdname} of {schoolName} has assign you an exam paper grading task." ],
+  "scan-join_groupList": [ "Join course notice", "{tmdname} join the {groupListName} course via QRcode scanning" ],
+  "scan-join_school": [ "Join school notice", "{tmdname} join school, {schoolName}, via QRcode scanning" ],
+  "submitanswer-school_homework": [ "Homework submission notice", "{tmdname} of {schoolName} has submitted a homework:{homeworkName}" ],
+  "submitanswer-private_homework": [ "Homework submission notice", "{tmdname} has submitted a homework({homeworkName})" ],
+  "expire-school_lessonRecord": [ "Lesson record expiration notice", "Your lesson record, {lessonName}, on {schoolName} will expire at {expireTime}" ],
+  "expire-private_lessonRecord": [ "Lesson record expiration notice", "Your lesson record, {lessonName} will expire at {expireTime}" ]
 }

+ 17 - 15
TEAMModelOS/Lang/zh-cn.json

@@ -1,18 +1,20 @@
-{
-  "request_school": [ "申请加入学校通知", "{tmdname}({tmdid})申请加入{schooName}。" ],
-  "invite_school": [ "邀请加入学校通知", "{schooName}邀请您加入学校。" ],
-  "remove_school": [ "从学校移除通知", "{schooName}将您从学校教师名单中移除。" ], 
-  "request-join_school": [ "同意申请加入学校通知", "{schooName}已同意您申请加入学校。" ],
-  "invite-join_school": [ "同意邀请加入学校通知", "{tmdname}已接受加入{schooName}的邀请。" ], 
-  "coedit_syllabus": [ "邀请共编课纲通知", "{tmdname}邀请你参与共编校本课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ], 
+{
+  "request_school": [ "申请加入学校通知", "{tmdname}({tmdid})申请加入{schoolName}。" ],
+  "invite_school": [ "邀请加入学校通知", "{schoolName}邀请您加入学校。" ],
+  "remove_school": [ "从学校移除通知", "{schoolName}将您从学校教师名单中移除。" ],
+  "request-join_school": [ "同意申请加入学校通知", "{schoolName}已同意您申请加入学校。" ],
+  "invite-join_school": [ "同意邀请加入学校通知", "{tmdname}已接受加入{schoolName}的邀请。" ],
+  "coedit_syllabus": [ "邀请共编课纲通知", "{schoolName}的{tmdname}邀请你参与共编校本课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ],
+  "coedit_volume": [ "邀请共编册别通知", "{schoolName}的{tmdname}邀请你参与共编校本册别,册别名称:{volumeName}。" ],
   "share_syllabus": [ "课纲分享接收通知", "{tmdname}向您分享了个人课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ],
-  "transfer-admin_school": [ "管理员移交通知", "{tmdname}将{schooName}的管理员移交给您。" ], 
-  "scoring-arb_school": [ "仲裁卷阅卷任务通知", "{schoolname}的{tmdname}向您发送了仲裁卷阅卷任务。" ], 
-  "scoring-err_school": [ "异常卷阅卷任务通知", "{schoolname}的{tmdname}向您发送了异常卷阅卷任务。" ],
-  "scoring-mark_school": [ "普通阅卷任务通知", "{schoolname}的{tmdname}向您发送了普通卷阅卷任务。" ],
-  "scan-join_groupList": [ "扫码加入名单通知", "{tmdname}扫码加入名单,名单:{groupListName}" ], 
+  "transfer-admin_school": [ "管理员移交通知", "{tmdname}将{schoolName}的管理员移交给您。" ],
+  "scoring-arb_school": [ "仲裁卷阅卷任务通知", "{schoolName}的{tmdname}向您发送了仲裁卷阅卷任务。" ],
+  "scoring-err_school": [ "异常卷阅卷任务通知", "{schoolName}的{tmdname}向您发送了异常卷阅卷任务。" ],
+  "scoring-mark_school": [ "普通阅卷任务通知", "{schoolName}的{tmdname}向您发送了普通卷阅卷任务。" ],
+  "scan-join_groupList": [ "扫码加入名单通知", "{tmdname}扫码加入名单,名单:{groupListName}" ],
   "scan-join_school": [ "扫码加入学校通知", "{tmdname}扫码加入学校,学校名称:{schoolName}" ],
-  "submitanswer_homework": [ "作业提交通知", "{tmdname}已提交作业,作业名称({homeworkName})" ], 
-  "expire-school_lessonRecord": [ "课例到期通知", "您在{schoolname}的课例将在{expireTime}到期,课例名称:{lessonRecordName}" ], 
-  "expire-private_lessonRecord": [ "课例到期通知", "您的课例将在{expireTime}到期,课例名称:{lessonRecordName}" ] 
+  "submitanswer-school_homework": [ "作业提交通知", "{schoolName}的{tmdname}已提交作业,作业名称:{homeworkName}" ],
+  "submitanswer-private_homework": [ "作业提交通知", "{tmdname}已提交作业,作业名称({homeworkName})" ],
+  "expire-school_lessonRecord": [ "课例到期通知", "您在{schoolName}的课例将在{expireTime}到期,课例名称:{lessonName}" ],
+  "expire-private_lessonRecord": [ "课例到期通知", "您的课例将在{expireTime}到期,课例名称:{lessonName}" ]
 }

+ 19 - 17
TEAMModelOS/Lang/zh-tw.json

@@ -1,18 +1,20 @@
-{
-  "request_school": [ "申请加入学校通知", "{tmdname}({tmdid})申请加入{schooName}。" ], 
-  "invite_school": [ "邀请加入学校通知", "{schooName}邀请您加入学校。" ], 
-  "remove_school": [ "从学校移除通知", "{schooName}将您从学校教师名单中移除。" ],  
-  "request-join_school": [ "同意申请加入学校通知", "{schooName}已同意您申请加入学校。" ],  
-  "invite-join_school": [ "同意邀请加入学校通知", "{tmdname}已接受加入{schooName}的邀请。" ],  
-  "coedit_syllabus": [ "邀请共编课纲通知", "{tmdname}邀请你参与共编校本课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ], 
-  "share_syllabus": [ "课纲分享接收通知", "{tmdname}向您分享了个人课纲,册别名称:{volumeName},课纲节点名称:{syllabusName}。" ], 
-  "transfer-admin_school": [ "管理员移交通知", "{tmdname}将{schooName}的管理员移交给您。" ],  
-  "scoring-arb_school": [ "仲裁卷阅卷任务通知", "{schoolname}的{tmdname}向您发送了仲裁卷阅卷任务。" ], 
-  "scoring-err_school": [ "异常卷阅卷任务通知", "{schoolname}的{tmdname}向您发送了异常卷阅卷任务。" ],  
-  "scoring-mark_school": [ "普通阅卷任务通知", "{schoolname}的{tmdname}向您发送了普通卷阅卷任务。" ],  
-  "scan-join_groupList": [ "扫码加入名单通知", "{tmdname}扫码加入名单,名单:{groupListName}" ],  
-  "scan-join_school": [ "扫码加入学校通知", "{tmdname}扫码加入学校,学校名称:{schoolName}" ],  
-  "submitanswer_homework": [ "作业提交通知", "{tmdname}已提交作业,作业名称({homeworkName})" ], 
-  "expire-school_lessonRecord": [ "课例到期通知", "您在{schoolname}的课例将在{expireTime}到期,课例名称:{lessonRecordName}" ],  
-  "expire-private_lessonRecord": [ "课例到期通知", "您的课例将在{expireTime}到期,课例名称:{lessonRecordName}" ]  
+{
+  "request_school": [ "申請加入學校通知", "{tmdname}({tmdid})申請加入{schoolName}。" ],
+  "invite_school": [ "邀請加入學校通知", "{schoolName}邀請您加入學校。" ],
+  "remove_school": [ "從學校移除通知", "{schoolName}將您從學校教師名單中移除。" ],
+  "request-join_school": [ "同意申請加入學校通知", "{schoolName}已同意您申請加入學校。" ],
+  "invite-join_school": [ "同意邀請加入學校通知", "{tmdname}已接受加入{schoolName}的邀請。" ],
+  "coedit_syllabus": [ "邀請共編課綱通知", "{schoolName}的{tmdname}邀請你參與共編校本課綱,冊別名稱:{volumeName},課綱節點名稱:{syllabusName}。" ],
+  "coedit_volume": [ "邀請共編冊別通知", "{schoolName}的{tmdname}邀請你參與共編校本冊別,冊別名稱:{volumeName}。" ],
+  "share_syllabus": [ "課綱分享接收通知", "{tmdname}向您分享了個人課綱,冊別名稱:{volumeName},課綱節點名稱:{syllabusName}。" ],
+  "transfer-admin_school": [ "管理員移交通知", "{tmdname}將{schoolName}的管理員移交給您。" ],
+  "scoring-arb_school": [ "仲裁卷閱卷任務通知", "{schoolName}的{tmdname}向您發送了仲裁卷閱卷任務。" ],
+  "scoring-err_school": [ "異常卷閱卷任務通知", "{schoolName}的{tmdname}向您發送了異常卷閱卷任務。" ],
+  "scoring-mark_school": [ "普通閱卷任務通知", "{schoolName}的{tmdname}向您發送了普通卷閱卷任務。" ],
+  "scan-join_groupList": [ "掃碼加入名單通知", "{tmdname}掃碼加入名單,名單:{groupListName}" ],
+  "scan-join_school": [ "掃碼加入學校通知", "{tmdname}掃碼加入學校,學校名稱:{schoolName}" ],
+  "submitanswer-school_homework": [ "作業提交通知", "{schoolName}的{tmdname}已提交作業,作業名稱:{homeworkName}" ],
+  "submitanswer-private_homework": [ "作業提交通知", "{tmdname}已提交作業,作業名稱({homeworkName})" ],
+  "expire-school_lessonRecord": [ "課例到期通知", "您在{schoolName}的課例將在{expireTime}到期,課例名稱:{lessonName}" ],
+  "expire-private_lessonRecord": [ "課例到期通知", "您的課例將在{expireTime}到期,課例名稱:{lessonName}" ]
 }

+ 8 - 9
TEAMModelOS/appsettings.Development.json

@@ -21,23 +21,22 @@
   },
   "Azure": {
     "Storage": {
-      "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodeltest;AccountKey=O2W2vadCqexDxWO+px+QK7y1sHwsYj8f/WwKLdOdG5RwHgW/Dupz9dDUb4c1gi6ojzQaRpFUeAAmOu4N9E+37A==;EndpointSuffix=core.chinacloudapi.cn"
+      "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelos;AccountKey=Dl04mfZ9hE9cdPVO1UtqTUQYN/kz/dD/p1nGvSq4tUu/4WhiKcNRVdY9tbe8620nPXo/RaXxs+1F9sVrWRo0bg==;EndpointSuffix=core.chinacloudapi.cn"
     },
     "Cosmos": {
-      "ConnectionString": "AccountEndpoint=https://cdhabookdep-free.documents.azure.cn:443/;AccountKey=JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A==;"
-      //"ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;"
+      "ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;"
     },
     "Redis": {
-      "ConnectionString": "52.130.252.100:6379,password=habook,ssl=false,abortConnect=False,writeBuffer=10240"
+      "ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False"
     },
     "ServiceBus": {
-      "ConnectionString": "Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=",
-      "ActiveTask": "dep-active-task",
-      "ItemCondQueue": "dep-itemcond",
-      "GenPdfQueue": "dep-genpdf"
+      "ConnectionString": "Endpoint=sb://coreiotservicebuscnpro.servicebus.chinacloudapi.cn/;SharedAccessKeyName=TEAMModelOS;SharedAccessKey=llRPBMDJG9w1Nnifj+pGhV0g4H2REcq0PjvX2qqpcOg=",
+      "ActiveTask": "active-task",
+      "ItemCondQueue": "itemcond",
+      "GenPdfQueue": "genpdf"
     },
     "SignalR": {
-      "ConnectionString": "Endpoint=https://channel.service.signalr.net;AccessKey=KrblW06tuA4a/GyqRPDU0ynFFmAWxbAvyJihHclSXbQ=;Version=1.0;"
+      "ConnectionString": "Endpoint=https://channel.signalr.azure.cn;AccessKey=AtcB7JYFNUbUXb1rGxa3PVksQ2X5YSv3JOHZR9J88tw=;Version=1.0;"
     }
   },
   "HaBookAuth": {