CrazyIter_Bin 3 년 전
부모
커밋
8b4bb40b94
100개의 변경된 파일3703개의 추가작업 그리고 3803개의 파일을 삭제
  1. BIN
      TEAMModeBI/ClientApp/public/favicon.ico
  2. 2 2
      TEAMModeBI/ClientApp/public/index.html
  3. BIN
      TEAMModeBI/ClientApp/src/assets/img/logox.png
  4. 139 194
      TEAMModeBI/ClientApp/src/components/AbilityTree.vue
  5. 1 1
      TEAMModeBI/ClientApp/src/components/echarts/basicPie.vue
  6. 1 1
      TEAMModeBI/ClientApp/src/components/echarts/chinaMap.vue
  7. 1 1
      TEAMModeBI/ClientApp/src/store/index.js
  8. 9 1
      TEAMModeBI/ClientApp/src/until/inspect.js
  9. 109 12
      TEAMModeBI/ClientApp/src/view/common/aside.vue
  10. 15 14
      TEAMModeBI/ClientApp/src/view/created/created.vue
  11. 1 1
      TEAMModeBI/ClientApp/src/view/home.vue
  12. 4 3
      TEAMModeBI/ClientApp/src/view/index/dashboard.vue
  13. 12 11
      TEAMModeBI/ClientApp/src/view/teachermanage/areamanage.vue
  14. 9 9
      TEAMModeBI/ClientApp/src/view/teachermanage/manage.vue
  15. 17 17
      TEAMModeBI/ClientApp/src/view/teachermanage/school.vue
  16. 22 23
      TEAMModeBI/ClientApp/src/view/teachermanage/traitmanage.vue
  17. 14 55
      TEAMModeBI/Controllers/BIAbility/AbilityMgmtController.cs
  18. 16 40
      TEAMModeBI/Controllers/BIAbility/AbilityTaskMgmtController.cs
  19. 12 11
      TEAMModeBI/Controllers/BIHome/HomeStatisController.cs
  20. 7 14
      TEAMModeBI/Controllers/BISchool/AreaRelevantController.cs
  21. 8 220
      TEAMModeBI/Controllers/BISchool/BatchAreaController.cs
  22. 74 131
      TEAMModeBI/Controllers/BISchool/BatchSchoolController.cs
  23. 5 18
      TEAMModeBI/Controllers/BISchool/SchoolController.cs
  24. 53 17
      TEAMModeBI/Controllers/BITest/TestController.cs
  25. 4 18
      TEAMModeBI/Controllers/DingDingStruc/DDBackEndController.cs
  26. 15 62
      TEAMModeBI/Controllers/DingDingStruc/TableDingDingInfoController.cs
  27. 13 443
      TEAMModeBI/Controllers/LoginController.cs
  28. 15 28
      TEAMModeBI/Controllers/OperateRecord/OperateLogController.cs
  29. 165 0
      TEAMModeBI/Controllers/Product/ProductStatisController.cs
  30. 63 1
      TEAMModeBI/appsettings.json
  31. 58 6
      TEAMModelFunction/ScsApisHttpTrigger.cs
  32. 1 1
      TEAMModelOS.SDK/DI/HttpTrigger/HttpTrigger.cs
  33. 46 0
      TEAMModelOS.SDK/Helper/Common/TableHelper/OperateLogHelper.cs
  34. 55 0
      TEAMModelOS.SDK/Helper/Common/ValidatorHelper/ValidatorHelper.cs
  35. 0 58
      TEAMModelOS.SDK/Models/Cosmos/BI/OperateLog.cs
  36. 7 1
      TEAMModelOS.SDK/Models/Cosmos/School/Knowledge.cs
  37. 64 0
      TEAMModelOS.SDK/Models/Table/OperateLog.cs
  38. 23 7
      TEAMModelOS/ClientApp/public/index.html
  39. 2 2
      TEAMModelOS/ClientApp/src/common/AbilityUpload.vue
  40. 1 1
      TEAMModelOS/ClientApp/src/common/BaseUpload.vue
  41. 1 1
      TEAMModelOS/ClientApp/src/components/homework/BaseHwForm.vue
  42. 17 11
      TEAMModelOS/ClientApp/src/components/mark/MarkCanvas.vue
  43. 4 1
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/Homework.vue
  44. 1 1
      TEAMModelOS/ClientApp/src/components/student-web/SettingView/Setting.vue
  45. 3 5
      TEAMModelOS/ClientApp/src/components/syllabus/DragTree.vue
  46. 2 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/cusMgt.js
  47. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/researchCenter.js
  48. 136 135
      TEAMModelOS/ClientApp/src/locale/lang/en-US/stuAccount.js
  49. 16 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/syllabus.js
  50. 2 2
      TEAMModelOS/ClientApp/src/locale/lang/en-US/teachContent.js
  51. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/researchCenter.js
  52. 135 134
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/stuAccount.js
  53. 16 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/syllabus.js
  54. 2 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/teachContent.js
  55. 2 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/cusMgt.js
  56. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/researchCenter.js
  57. 136 135
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/stuAccount.js
  58. 25 9
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/syllabus.js
  59. 2 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/teachContent.js
  60. 1272 1252
      TEAMModelOS/ClientApp/src/router/routes.js
  61. 90 33
      TEAMModelOS/ClientApp/src/utils/blobTool.js
  62. 1 1
      TEAMModelOS/ClientApp/src/utils/evTools.js
  63. 3 3
      TEAMModelOS/ClientApp/src/utils/public.js
  64. 2 2
      TEAMModelOS/ClientApp/src/view/ability/TestPaper.vue
  65. 2 26
      TEAMModelOS/ClientApp/src/view/abilityMgmt/Index.vue
  66. 17 9
      TEAMModelOS/ClientApp/src/view/areaMgmt/AreaData.vue
  67. 11 5
      TEAMModelOS/ClientApp/src/view/areatrain/Create.vue
  68. 5 0
      TEAMModelOS/ClientApp/src/view/auth/Classroom.less
  69. 17 0
      TEAMModelOS/ClientApp/src/view/auth/Classroom.vue
  70. 49 0
      TEAMModelOS/ClientApp/src/view/auth/Index.less
  71. 80 0
      TEAMModelOS/ClientApp/src/view/auth/Index.vue
  72. 59 0
      TEAMModelOS/ClientApp/src/view/auth/Product.less
  73. 71 0
      TEAMModelOS/ClientApp/src/view/auth/Product.vue
  74. 192 0
      TEAMModelOS/ClientApp/src/view/auth/SpaceInfo.vue
  75. 0 71
      TEAMModelOS/ClientApp/src/view/authorization/Index.less
  76. 0 314
      TEAMModelOS/ClientApp/src/view/authorization/Index.vue
  77. 3 1
      TEAMModelOS/ClientApp/src/view/classmgt/ClassStudent.vue
  78. 2 2
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseEditExercise.vue
  79. 10 7
      TEAMModelOS/ClientApp/src/view/evaluation/index/CreateExercises.vue
  80. 5 9
      TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue
  81. 1 1
      TEAMModelOS/ClientApp/src/view/jyzx/offline.vue
  82. 3 2
      TEAMModelOS/ClientApp/src/view/knowledge-point/index/Index.vue
  83. 10 7
      TEAMModelOS/ClientApp/src/view/knowledge-point/index/operation/AddPoint.vue
  84. 3 1
      TEAMModelOS/ClientApp/src/view/learnactivity/ByQuMark.vue
  85. 14 13
      TEAMModelOS/ClientApp/src/view/learnactivity/ByStuMark.vue
  86. 53 34
      TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue
  87. 1 1
      TEAMModelOS/ClientApp/src/view/newsheet/index.vue
  88. 14 6
      TEAMModelOS/ClientApp/src/view/questionnaire/ManageQuestionnaire.vue
  89. 7 3
      TEAMModelOS/ClientApp/src/view/resource/Policy.vue
  90. 10 2
      TEAMModelOS/ClientApp/src/view/resource/SourceCenter.vue
  91. 12 10
      TEAMModelOS/ClientApp/src/view/schoolmgmt/SystemSetting/SystemSetting.less
  92. 0 19
      TEAMModelOS/ClientApp/src/view/sso/Index.vue
  93. 33 21
      TEAMModelOS/ClientApp/src/view/statistics/Dashboard.vue
  94. 22 44
      TEAMModelOS/ClientApp/src/view/statistics/TableData.vue
  95. 24 10
      TEAMModelOS/ClientApp/src/view/student-account/class/ClassMgt.vue
  96. 2 2
      TEAMModelOS/ClientApp/src/view/student-account/stulist/MgtStuList.less
  97. 6 1
      TEAMModelOS/ClientApp/src/view/student-account/stulist/MgtStuList.vue
  98. 18 18
      TEAMModelOS/ClientApp/src/view/syllabus/Syllabus.vue
  99. 13 11
      TEAMModelOS/ClientApp/src/view/task/mark/ByQu.vue
  100. 0 0
      TEAMModelOS/ClientApp/src/view/task/mark/ByQu2.vue

BIN
TEAMModeBI/ClientApp/public/favicon.ico


+ 2 - 2
TEAMModeBI/ClientApp/public/index.html

@@ -7,11 +7,11 @@
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
     <title>
-        <%= htmlWebpackPlugin.options.title %>
+        醍摩豆BI管理平台
     </title>
 </head>
 <script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
-<script src="https://at.alicdn.com/t/font_2934132_jkfde7zkwy.js"></script>
+<script src="https://at.alicdn.com/t/font_2934132_gkkks0q6atn.js"></script>
 
 <body>
     <noscript>

BIN
TEAMModeBI/ClientApp/src/assets/img/logox.png


+ 139 - 194
TEAMModeBI/ClientApp/src/components/AbilityTree.vue

@@ -70,8 +70,10 @@
     <div class="previewState">
         <el-dialog v-model="previewStates" width="60%" center>
             <p class="resource-title">{{detailsInfo.title}}</p>
-            <img :src="detailsInfo.url" v-if="detailsInfo.type==='image'">
-            <video v-else-if="detailsInfo.type == 'video'" id="previewVideo" :src="detailsInfo.url" width="870" controls="controls" autoplay style="max-height: 800px;">
+            <!-- <img :src="detailsInfo.url" v-if="detailsInfo.type==='image'"> -->
+            <el-image class="imagepreview" :src="detailsInfo.url" :preview-src-list="srcList" :initial-index="1" v-if="detailsInfo.type==='image'">
+            </el-image>
+            <video v-else-if="detailsInfo.type == 'video'" id="previewVideo" ref="videobox" :src="detailsInfo.url" width="870" controls="controls" autoplay style="max-height: 800px;">
                 {{detailsInfo.title}}
             </video>
             <audio v-else-if="detailsInfo.type == 'audio'" controls>
@@ -80,11 +82,21 @@
             </audio>
             <template #footer>
                 <span class="dialog-footer">
-                    <el-button @click="previewStates = false">关闭</el-button>
+                    <el-button @click="closebtn">关闭</el-button>
                 </span>
             </template>
         </el-dialog>
     </div>
+    <!--资源图片预览-->
+    <!-- <div class="demo-image__preview">
+        <el-image style="width: 100px; height: 100px" :src="detailsInfo.url" :preview-src-list="srcList" :initial-index="1" v-if="detailsInfo.type==='image'">
+        </el-image>
+    </div> -->
+    <!-- <div class="demo-image__preview">
+        <el-image style="width: 100px; height: 100px" :src="url" :preview-src-list="srcList" :initial-index="1">
+        </el-image>
+    </div> -->
+    <!--资源图片预览end-->
     <!--资源预览end-->
     <!--上传资源-->
     <div class="uploadFile">
@@ -173,6 +185,8 @@ export default {
         let watchModel = ref(true)
         let uploadRef = ref()
         let nomarl = ref([])
+        let videobox = ref()
+        let srcList = ref([])
         onMounted(() => {
             resourceData = resourceData.push(...props.tree)
             console.log(props.tree, '树状')
@@ -188,56 +202,7 @@ export default {
                 cancelButtonText: '取消',
             })
                 .then(({ value }) => {
-                    let ids = guid()
-                    console.log(value, data, user, ids, '确认后的')
-                    let newChild = { title: value, children: [], rnodes: [], id: ids, cids: [], creatorId: user.tmdId, creatorName: user.tmdName, pid: data.id, order: 0 }
-                    console.log(newChild)
-                    if (!data.children) {
-                        data.children = []
-                    }
-                    data.cids.push(newChild.id)
-                    data.children.push(newChild)
-                    console.log(data)
-                    console.log(props, '改变后的树状')
-                    let chidData = []
-                    for (let i in props.tree) {
-                        let dataOne = props.tree[i]
-                        if (data.id === dataOne.id) {
-                            chidData.push(dataOne)
-                        } else if (data.id !== dataOne.id && dataOne.children.length !== 0) {
-                            for (let y in dataOne.children) {
-                                if (data.id === dataOne.children[y].id) {
-                                    chidData.push(dataOne)
-                                } else if (data.id !== dataOne.children[y].id && dataOne.children[y].children.length !== 0) {
-                                    for (let u in dataOne.children[y].children) {
-                                        data.id === dataOne.children[y].children[u].id ? chidData.push(dataOne) : ''
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    console.log(chidData, '找到的最外层')
-                    let codeVals = ''
-                    let abilityIds = ''
-                    let scopes = ''
-                    let idInfo = ''
-                    for (let x in props.datas) {
-                        console.log(chidData[0].id, 'ID值')
-                        if (chidData[0].id === props.datas[x].id) {
-                            console.log(props.datas[x].id, '进入的值')
-                            codeVals = props.datas[x].codeval
-                            abilityIds = props.datas[x].abilityId
-                            scopes = props.datas[x].scope
-                            idInfo = props.datas[x].id
-                        }
-                    }
-                    let dataInfo = { abilityId: abilityIds, auth: [], codeval: codeVals, scope: scopes, id: idInfo, trees: chidData }
-                    let datas = { tmdId: user.tmdId, tmdName: user.tmdName, standard: props.stand, abilityTask: [dataInfo] }
-                    proxy.$api.addChild(datas).then((res) => {
-                        console.log(res, '增加子节点的返回')
-                        res.state === 200 ? ElMessage.success('节点添加成功') : ''
-                    })
-                    console.log(datas, '参数')
+                    onSaveData('', 'add', data, value)
                 })
                 .catch(() => {})
         }
@@ -262,44 +227,7 @@ export default {
                     deleteChapter(props.stand, receiveData.id, node)
                 } else {
                     let dataEvalue = nowPitchCb.value
-                    let user = JSON.parse(localStorage.getItem('userData'))
-                    let chidData = []
-                    //寻找最上级
-                    for (let i in props.tree) {
-                        let dataOne = props.tree[i]
-                        if (dataEvalue.id === dataOne.id) {
-                            chidData.push(dataOne)
-                        } else if (dataEvalue.id !== dataOne.id && dataOne.children.length !== 0) {
-                            for (let y in dataOne.children) {
-                                if (dataEvalue.id === dataOne.children[y].id) {
-                                    chidData.push(dataOne)
-                                } else if (dataEvalue.id !== dataOne.children[y].id && dataOne.children[y].children.length !== 0) {
-                                    for (let u in dataOne.children[y].children) {
-                                        dataEvalue.id === dataOne.children[y].children[u].id ? chidData.push(dataOne) : ''
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    //准备API参数
-                    let codeVals = ''
-                    let abilityIds = ''
-                    let scopes = ''
-                    let idInfo = ''
-                    for (let x in props.datas) {
-                        if (chidData[0].id === props.datas[x].id) {
-                            codeVals = props.datas[x].codeval
-                            abilityIds = props.datas[x].abilityId
-                            scopes = props.datas[x].scope
-                            idInfo = props.datas[x].id
-                        }
-                    }
-                    let dataInfo = { abilityId: abilityIds, auth: [], codeval: codeVals, scope: scopes, id: idInfo, trees: chidData }
-                    let datas = { tmdId: user.tmdId, tmdName: user.tmdName, standard: props.stand, abilityTask: [dataInfo] }
-                    proxy.$api.addChild(datas).then((res) => {
-                        console.log(res, '删除子节点的返回')
-                        res.state === 200 ? ElMessage.success('节点删除成功') : ElMessage.error('节点删除失败')
-                    })
+                    onSaveData(dataEvalue, 'delete')
                     const parent = node.parent
                     const children = parent.data.children || parent.data
                     const index = children.findIndex((d) => d.id === data.id)
@@ -375,6 +303,13 @@ export default {
                 window.open('https://www.teammodel.cn/web/viewer.html?file=' + encodeURIComponent(urls))
             } else if (val.type === 'doc') {
                 window.open('https://view.officeapps.live.com/op/view.aspx?src=' + encodeURIComponent(urls))
+            } else if (val.type === 'image') {
+                detailsInfo.value.title = val.title
+                detailsInfo.value.type = val.type
+                detailsInfo.value.id = val.id
+                detailsInfo.value.url = urls
+                detailsInfo.value.url ? (previewStates.value = true) : ''
+                srcList.value.push(urls)
             } else {
                 detailsInfo.value.title = val.title
                 detailsInfo.value.type = val.type
@@ -415,7 +350,7 @@ export default {
                 res.url ? ElMessage.success('上传成功') : ElMessage.error('上传失败')
                 uploadList.value.push(res)
                 let datas = curNode.value
-                datas.push({ title: res.name, link: res.blob, size: res.size, type: res.type, id: guid(), cntr: 'teammodelos' })
+                datas.push({ title: res.name, link: res.blob, size: res.size, type: res.type, id: proxy.$access.guid(), cntr: 'teammodelos' })
                 curNode.value = datas
                 uploadBtn.value = false
                 uploadFiles.value = false
@@ -423,55 +358,15 @@ export default {
             })
         }
         //存储变更
-        function changes() {
+        async function changes() {
             let data = nowPitchCb.value
-            let user = JSON.parse(localStorage.getItem('userData'))
-            console.log(data, '变更数据')
-            let chidData = []
-            //寻找最上级
-            for (let i in props.tree) {
-                let dataOne = props.tree[i]
-                if (data.id === dataOne.id) {
-                    chidData.push(dataOne)
-                } else if (data.id !== dataOne.id && dataOne.children.length !== 0) {
-                    for (let y in dataOne.children) {
-                        if (data.id === dataOne.children[y].id) {
-                            chidData.push(dataOne)
-                        } else if (data.id !== dataOne.children[y].id && dataOne.children[y].children.length !== 0) {
-                            for (let u in dataOne.children[y].children) {
-                                data.id === dataOne.children[y].children[u].id ? chidData.push(dataOne) : ''
-                            }
-                        }
-                    }
-                }
-            }
-            //准备API参数
-            let codeVals = ''
-            let abilityIds = ''
-            let scopes = ''
-            let idInfo = ''
-            for (let x in props.datas) {
-                if (chidData[0].id === props.datas[x].id) {
-                    console.log(props.datas[x].id, '进入的值')
-                    codeVals = props.datas[x].codeval
-                    abilityIds = props.datas[x].abilityId
-                    scopes = props.datas[x].scope
-                    idInfo = props.datas[x].id
-                }
-            }
-            let dataInfo = { abilityId: abilityIds, auth: [], codeval: codeVals, scope: scopes, id: idInfo, trees: chidData }
-            let datas = { tmdId: user.tmdId, tmdName: user.tmdName, standard: props.stand, abilityTask: [dataInfo] }
-            proxy.$api.addChild(datas).then((res) => {
-                console.log(res, '存储变更的返回')
-                res.state === 200 ? (ElMessage.success('储存变更成功'), (uploadList.value = [])) : ElMessage.error('储存变更失败')
-                uploadFileData.value = []
-            })
+            await onSaveData(data, 'save')
             setTimeout((watchModel.value = true), '2000')
         }
         //删除资源
         function deleteResource(val, index) {
             watchModel.value = false
-            console.log(val)
+            console.log(watchModel.value, '删除操作的值')
             let urlHost = JSON.parse(localStorage.getItem('blobInfo'))
             let urlheader = urlHost.osblob_uri.substring(0, urlHost.osblob_uri.indexOf('cn') + 2)
             let space = urlHost.osblob_uri.slice(urlHost.osblob_uri.indexOf('cn') + 3)
@@ -491,54 +386,9 @@ export default {
                         if (res === 200) {
                             curNode.value.splice(index, 1)
                             let data = nowPitchCb.value
-                            console.log(props, '现在的数据')
-                            console.log(data, '现在选中的')
-                            let chidData = []
-                            for (let i in props.tree) {
-                                let dataOne = props.tree[i]
-                                if (data.id === dataOne.id) {
-                                    chidData.push(dataOne)
-                                } else if (data.id !== dataOne.id && dataOne.children.length !== 0) {
-                                    for (let y in dataOne.children) {
-                                        if (data.id === dataOne.children[y].id) {
-                                            chidData.push(dataOne)
-                                        } else if (data.id !== dataOne.children[y].id && dataOne.children[y].children.length !== 0) {
-                                            for (let u in dataOne.children[y].children) {
-                                                data.id === dataOne.children[y].children[u].id ? chidData.push(dataOne) : ''
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                            //准备API参数
-                            let codeVals = ''
-                            let abilityIds = ''
-                            let scopes = ''
-                            let idInfo = ''
-                            for (let x in props.datas) {
-                                if (chidData[0].id === props.datas[x].id) {
-                                    console.log(props.datas[x].id, '进入的值')
-                                    codeVals = props.datas[x].codeval
-                                    abilityIds = props.datas[x].abilityId
-                                    scopes = props.datas[x].scope
-                                    idInfo = props.datas[x].id
-                                }
-                            }
-                            let dataInfo = { abilityId: abilityIds, auth: [], codeval: codeVals, scope: scopes, id: idInfo, trees: chidData }
-                            let datas = { tmdId: user.tmdId, tmdName: user.tmdName, standard: props.stand, abilityTask: [dataInfo] }
-                            proxy.$api.addChild(datas).then((res) => {
-                                console.log(res, '删除的API返回')
-                                res.state === 200
-                                    ? (ElMessage.success('删除成功'),
-                                      uploadList.value.forEach((item, index) => {
-                                          item.blob === val.link ? uploadList.value.splice(index, 1) : ''
-                                      }))
-                                    : ElMessage.error('删除失败')
-                                setTimeout((watchModel.value = true), '2000')
-                            })
+                            onSaveData(data, 'deleteResource')
                         } else {
                             ElMessage.warning('删除失败')
-                            setTimeout((watchModel.value = true), '2000')
                         }
                     })
                 })
@@ -551,7 +401,8 @@ export default {
                 confirmButtonText: '确认',
                 cancelButtonText: '取消',
             }).then(({ value }) => {
-                let ids = guid()
+                watchModel.value = false
+                let ids = proxy.$access.guid()
                 console.log(props, '这是添加第一级用到的父ID')
                 let datsiof = []
                 let newChild = { title: value, children: [], rnodes: [], id: ids, cids: [], creatorId: user.tmdId, creatorName: user.tmdName, pid: props.abilityId, order: 0 }
@@ -562,10 +413,11 @@ export default {
                 let datas = { tmdId: user.tmdId, tmdName: user.tmdName, standard: props.stand, abilityTask: [dataInfo] }
                 proxy.$api.addChild(datas).then((res) => {
                     console.log(res, '这是创建第一级的父节点的API返回')
-                    res.state === 200 ? ElMessage.success('节点创建成功') : ElMessage.error('节点创建失败')
+                    res.state === 200 ? (ElMessage.success('节点创建成功'), treeRef.value.setCurrentKey(res.recordAbilityTask.abilityTask[0].id)) : ElMessage.error('节点创建失败')
                 })
                 console.log(datas, '参数')
             })
+            setTimeout((watchModel.value = true), '2000')
         }
         //删除父节点(tree一级@章节)
         function deleteChapter(standard, chapterId, node) {
@@ -590,13 +442,84 @@ export default {
             let pattern = /[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?/
             return s.split('//')[0] + '//' + s.match(pattern)[0]
         }
-        //GUID生成
-        function guid() {
-            return randomId() + randomId() + '-' + randomId() + '-' + randomId() + '-' + randomId() + '-' + randomId() + randomId() + randomId()
+        //最后的保存数据操作
+        function onSaveData(value, operate, dataWork, titleName) {
+            let dataEvalue = value
+            let data = dataWork
+            let user = JSON.parse(localStorage.getItem('userData'))
+            if (operate === 'add') {
+                let ids = proxy.$access.guid()
+                let newChild = { title: titleName, children: [], rnodes: [], id: ids, cids: [], creatorId: user.tmdId, creatorName: user.tmdName, pid: data.id, order: 0 }
+                console.log(newChild)
+                if (!data.children) {
+                    data.children = []
+                }
+                data.cids.push(newChild.id)
+                data.children.push(newChild)
+                dataEvalue = data
+            }
+            let chidData = []
+            //寻找最上级
+            for (let i in props.tree) {
+                let dataOne = props.tree[i]
+                if (dataEvalue.id === dataOne.id) {
+                    chidData.push(dataOne)
+                } else if (dataEvalue.id !== dataOne.id && dataOne.children.length !== 0) {
+                    for (let y in dataOne.children) {
+                        if (dataEvalue.id === dataOne.children[y].id) {
+                            chidData.push(dataOne)
+                        } else if (dataEvalue.id !== dataOne.children[y].id && dataOne.children[y].children.length !== 0) {
+                            for (let u in dataOne.children[y].children) {
+                                dataEvalue.id === dataOne.children[y].children[u].id ? chidData.push(dataOne) : ''
+                            }
+                        }
+                    }
+                }
+            }
+            //准备API参数
+            let codeVals = ''
+            let abilityIds = ''
+            let scopes = ''
+            let idInfo = ''
+            for (let x in props.datas) {
+                if (chidData[0].id === props.datas[x].id) {
+                    codeVals = props.datas[x].codeval
+                    abilityIds = props.datas[x].abilityId
+                    scopes = props.datas[x].scope
+                    idInfo = props.datas[x].id
+                }
+            }
+            let msgInfo = ''
+            let dataInfo = { abilityId: abilityIds, auth: [], codeval: codeVals, scope: scopes, id: idInfo, trees: chidData }
+            let datas = { tmdId: user.tmdId, tmdName: user.tmdName, standard: props.stand, abilityTask: [dataInfo] }
+            proxy.$api.addChild(datas).then((res) => {
+                // operate === 'delete' ? (msgInfo = '节点删除') : ''
+                // operate === 'add' ? (msgInfo = '节点创建') : ''
+                // res.state === 200 ? ElMessage.success(`{{msgInfo}}成功`) : ElMessage.error(`{{msgInfo}}失败`)
+                if (operate === 'add') {
+                    res.state === 200 ? ElMessage.success('节点创建成功') : ElMessage.error('节点创建失败')
+                } else if (operate === 'delete') {
+                    res.state === 200 ? ElMessage.success('节点删除成功') : ElMessage.error('节点删除失败')
+                } else if (operate === 'save') {
+                    res.state === 200 ? (ElMessage.success('储存变更成功'), (uploadList.value = [])) : ElMessage.error('储存变更失败')
+                    uploadFileData.value = []
+                } else if (operate === 'deleteResource') {
+                    console.log(watchModel.value, '删除资源当前的值')
+                    res.state === 200
+                        ? (ElMessage.success('资源删除成功'),
+                          uploadList.value.forEach((item, index) => {
+                              item.blob === val.link ? uploadList.value.splice(index, 1) : ''
+                          }),
+                          setTimeout((watchModel.value = true), '2000'))
+                        : (ElMessage.error('资源删除失败'), setTimeout((watchModel.value = true), '2000'))
+                }
+            })
         }
-        // 生成随机UUID工具
-        function randomId() {
-            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
+        //查看资源 关闭视频
+        function closebtn() {
+            previewStates.value = false
+            console.log(videobox, '视频')
+            videobox.value ? videobox.value.pause() : ''
         }
         watch(
             props,
@@ -606,7 +529,9 @@ export default {
                     if (watchModel.value) {
                         treeRef.value.setCurrentKey(nweProps.defaultinfo)
                         fileList.value.id = nweProps.defaultinfo
-                        curNode.value = nweProps.tree[0].rnodes
+                        // curNode.value = nweProps.tree[0].rnodes
+                        console.log(nweProps)
+                        nweProps.tree.length !== 0 && nweProps.tree[0].rnodes ? (curNode.value = nweProps.tree[0].rnodes) : (curNode.value = [])
                     }
                 })
             },
@@ -631,8 +556,6 @@ export default {
             resourceData,
             pitchNow,
             treeRef,
-            guid,
-            randomId,
             uploadFiles,
             uploadResource,
             fileList,
@@ -649,6 +572,10 @@ export default {
             openUpload,
             nomarl,
             uploadRef,
+            onSaveData,
+            closebtn,
+            videobox,
+            srcList,
         }
     },
 }
@@ -664,7 +591,7 @@ export default {
     width: 600px;
     border-right: 1px dashed rgb(180, 178, 178);
     padding-right: 20px;
-    height: 88vh;
+    height: 85vh;
     margin-top: 35px;
     overflow: hidden;
 }
@@ -676,7 +603,7 @@ export default {
 }
 .right-box {
     width: 54%;
-    height: 88vh;
+    height: 85vh;
     margin-top: 35px;
 }
 .el-tree-node__content {
@@ -889,4 +816,22 @@ export default {
     width: 100%;
     height: 40px;
 }
+.imagepreview {
+    margin: 0 auto;
+    max-width: 1100px;
+    max-height: 600px;
+}
+#previewVideo {
+    width: 100%;
+}
+@media screen and (max-width: 1366px) {
+    .mainBox .column .panel .chart {
+        height: 11vh;
+    }
+}
+@media screen and (max-width: 1920px) {
+    .mainBox .column .panel .chart {
+        height: 16vh;
+    }
+}
 </style>

+ 1 - 1
TEAMModeBI/ClientApp/src/components/echarts/basicPie.vue

@@ -68,7 +68,7 @@ class InitChart {
                 },
             },
             legend: {
-                top: '85%',
+                top: '75%',
                 itemWidth: 10,
                 itemHeight: 10,
                 data: datas.legendData,

+ 1 - 1
TEAMModeBI/ClientApp/src/components/echarts/chinaMap.vue

@@ -131,7 +131,7 @@ class InitChart {
                 map: 'china',
                 show: true,
                 roam: false,
-                zoom: 1.25,
+                zoom: 1.1,
                 label: {
                     normal: {
                         show: false,

+ 1 - 1
TEAMModeBI/ClientApp/src/store/index.js

@@ -6,7 +6,7 @@ export default createStore({
         teachUserdata: [], //教室个人信息
         binDingstatus: true,
         schoolMenu: [],
-        sidebarstatus: { "width": "200px", "isCollapses": false }, //侧边栏状态值
+        sidebarstatus: { "width": "64px", "isCollapses": true }, //侧边栏状态值
         point: [],
         userBlob: {
             "host": '',

+ 9 - 1
TEAMModeBI/ClientApp/src/until/inspect.js

@@ -7,5 +7,13 @@ export default {
         console.log(result, '状态值')
         userStatus.roles === "admin" ? result = true : ''
         return result
-    }
+    },
+    // 生成随机UUID工具
+    randomId() {
+        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
+    },
+    //GUID生成
+    guid() {
+        return this.randomId() + this.randomId() + '-' + this.randomId() + '-' + this.randomId() + '-' + this.randomId() + '-' + this.randomId() + this.randomId() + this.randomId()
+    },
 }

+ 109 - 12
TEAMModeBI/ClientApp/src/view/common/aside.vue

@@ -1,11 +1,14 @@
 <template>
-    <div id="asidebox">
-        <el-aside :width="menuWidth" style="background-color: rgb(238, 241, 246)">
-            <el-radio-group v-model="isCollapse" style="margin-bottom: 20px">
+    <div id="asidebox" class="MenuBox" @mouseover="mouseOver" @mouseleave="mouseLeave" style="background-color:#1d1e23">
+        <div class="logobox">
+            <img src="@/assets/img/logox.png">
+        </div>
+        <el-aside :width="menuWidth">
+            <!-- <el-radio-group v-model="isCollapse" style="margin-bottom: 20px">
                 <el-radio-button :label="false" @click="menuWidth=200+'px';isCollapse=false" v-show="isCollapse ==true"><i class="el-icon-s-unfold"></i></el-radio-button>
                 <el-radio-button :label="true" @click="menuWidth=64+'px';isCollapse=true" v-show="isCollapse ==false"><i class="el-icon-s-fold"></i></el-radio-button>
-            </el-radio-group>
-            <el-menu default-active="1-0" class="el-menu-vertical-demo" :collapse="isCollapse" @select="handleSelect" v-for="(item,index) in menuList" :key="index">
+            </el-radio-group> -->
+            <el-menu :default-active="indexMenu" class="el-menu-vertical-demo" :collapse="isCollapse" @select="handleSelect" v-for="(item,index) in menuList" :key="index" :collapse-transition="locksetting" background-color="#1d1e23" text-color="#fff">
                 <el-sub-menu :index="index" v-if="item.child.length">
                     <template #title>
                         <svg class="icon" aria-hidden="true">
@@ -29,6 +32,11 @@
                     <span @click="routerskip(item.router)">{{item.name}}</span>
                 </el-menu-item>
             </el-menu>
+            <div class="locks" :title='locktitle'>
+                <svg class="lockicon" aria-hidden="true" @click="lockMenu">
+                    <use :xlink:href="lockicon"></use>
+                </svg>
+            </div>
         </el-aside>
     </div>
 </template>
@@ -99,13 +107,20 @@ export default {
         IconMenu,
     },
     setup() {
-        console.log(schoolMenus, '查看根源')
+        console.log('调用了一次这个页面')
         let { proxy } = getCurrentInstance()
-        let menuWidth = ref('')
+        let menuWidth = ref('64px')
         var menuList = ref([])
-        const isCollapse = ref(false)
+        const isCollapse = ref(true)
         const store = useStore()
         const shenfen = ref('admin')
+        let indexMenu = ref('1-0')
+        let indexsinfo = ref()
+        let lockState = ref(true)
+        let locktitle = ref('锁定菜单栏')
+        let lockicon = ref('#icon-weisuoding-copy')
+        let locksetting = ref(false)
+        console.log(indexMenu.value, '类型')
         // store.commit('routerMenu', schoolMenus)
         onMounted(() => {
             console.log(schoolMenus, '初始的')
@@ -131,7 +146,6 @@ export default {
                 }
             }
             console.log(menuList.value, '菜单')
-            var btn = document.getElementById('asidebox')
             var timer = null
             // btn.onmouseover = btn.onmouseover = function () {
             //     isCollapse.value = false
@@ -147,8 +161,8 @@ export default {
         watch(
             store.state,
             () => {
-                isCollapse.value = store.state.sidebarstatus.isCollapses
-                menuWidth.value = store.state.sidebarstatus.width
+                // isCollapse.value = store.state.sidebarstatus.isCollapses
+                // menuWidth.value = store.state.sidebarstatus.width
             },
             { immediate: true, deep: true }
         )
@@ -165,6 +179,42 @@ export default {
             console.log(proxy)
             router.push(val)
         }
+        function mouseOver() {
+            if (lockState.value) {
+                var lockInfo = document.getElementsByClassName('locks')
+                var asibox = document.getElementsByClassName('MenuBox')
+                isCollapse.value = false
+                lockInfo[0].style.width = 200 + 'px'
+                asibox[0].style.width = 199 + 'px'
+                menuWidth.value = 200 + 'px'
+            }
+        }
+        function mouseLeave() {
+            if (lockState.value) {
+                var lockInfo = document.getElementsByClassName('locks')
+                var asibox = document.getElementsByClassName('MenuBox')
+                isCollapse.value = true
+                lockInfo[0].style.width = 64 + 'px'
+                asibox[0].style.width = 63 + 'px'
+                menuWidth.value = 64 + 'px'
+            }
+        }
+        function lockMenu() {
+            if (lockState.value) {
+                var lockInfo = document.getElementsByClassName('locks')
+                var asibox = document.getElementsByClassName('MenuBox')
+                lockState.value = false
+                isCollapse.value = false
+                lockInfo[0].style.width = 200 + 'px'
+                asibox[0].style.width = 199 + 'px'
+                menuWidth.value = 200 + 'px'
+                locktitle.value = '解锁菜单栏'
+                lockicon.value = '#icon-suoding-copy'
+            } else {
+                lockState.value = true
+                lockicon.value = '#icon-weisuoding-copy'
+            }
+        }
         return {
             menuList,
             schoolMenus,
@@ -175,11 +225,21 @@ export default {
             handleClose,
             handleSelect,
             routerskip,
+            mouseOver,
+            mouseLeave,
+            locktitle,
+            lockMenu,
+            lockicon,
+            locksetting,
+            indexMenu,
         }
     },
 }
 </script>
 <style>
+.asidebox {
+    position: relative;
+}
 .el-aside {
     background-color: #d3dce6;
     color: var(--el-text-color-primary);
@@ -229,7 +289,8 @@ body > .el-container {
 .el-radio-button {
     background-color: rgb(238, 241, 246) !important;
 }
-.icon {
+.icon,
+.lockicon {
     width: 1.5em;
     height: 1.5em;
     vertical-align: -0.5em;
@@ -237,4 +298,40 @@ body > .el-container {
     overflow: hidden;
     margin-right: 5px;
 }
+.lockicon {
+    width: 1em;
+    height: 1em;
+    vertical-align: 0em;
+    fill: currentColor;
+    overflow: hidden;
+    margin-right: 5px;
+}
+.lockicon:hover {
+    cursor: pointer;
+}
+.locks {
+    position: absolute;
+    width: 64px;
+    text-align: center;
+    bottom: 0%;
+    line-height: 40px;
+    border-top: 1px solid #ccc;
+}
+.MenuBox {
+    width: 63px;
+}
+.viewbox .el-header {
+    background-color: #1d1e23 !important;
+    opacity: 0.97 !important;
+    border-bottom: 2px solid #1cc0f3;
+}
+.viewbox .el-main {
+    background-color: #fdfdfd;
+}
+.logobox {
+    width: 100%;
+    line-height: 58px;
+    border-bottom: 2px solid #1cc0f3;
+    text-align: center;
+}
 </style>

+ 15 - 14
TEAMModeBI/ClientApp/src/view/created/created.vue

@@ -62,7 +62,7 @@
                         </div>
                         <div class="dist-box">
                             <span>区域:</span>
-                            <el-select v-model="distOptions.distValue" filterable="true" allow-create default-first-option placeholder="区域选择" @change="areaSelctChange(distOptions.distValue,'dist')">
+                            <el-select v-model="distOptions.distValue" allow-create default-first-option placeholder="区域选择" @change="areaSelctChange(distOptions.distValue,'dist')">
                                 <el-option v-for="item in distOptions.distInfo" :key="item.code" :label="item.name" :value="item.name">
                                 </el-option>
                             </el-select>
@@ -85,7 +85,7 @@
                         </div>
                         <div class="dist-box">
                             <span>区域:</span>
-                            <el-select v-model="distOptions.distValue" placeholder="区域选择" disabled>
+                            <el-select v-model="distOptions.distValue" filterable placeholder="区域选择" disabled>
                                 <el-option v-for="item in distOptions.distInfo" :key="item.code" :label="item.name" :value="item.name">
                                 </el-option>
                             </el-select>
@@ -172,7 +172,7 @@
                         </div>
                         <div class="dist-box">
                             <span>区域:</span>
-                            <el-select v-model="distOptions.distValue" filterable="true" allow-create default-first-option placeholder="区域选择" @change="areaSelctChange(distOptions.distValue,'dist',item.num)">
+                            <el-select v-model="distOptions.distValue" filterable allow-create default-first-option placeholder="区域选择" @change="areaSelctChange(distOptions.distValue,'dist',item.num)">
                                 <el-option v-for="item in distOptions.distInfo" :key="item.code" :label="item.name" :value="item.name">
                                 </el-option>
                             </el-select>
@@ -229,16 +229,16 @@
             <p>列表总数:{{batchData.length}}</p>
             <div class="batch-table">
                 <el-table :data="batchData" style="width: 100%">
-                    <el-table-column prop="index" label="编号" width="100" type=index align="center" />
-                    <el-table-column prop="name" label="名称" width="200" align="center" />
-                    <el-table-column prop="admin" label="管理关联账号" width="150" align="center" />
-                    <el-table-column prop="period" label="学段" width="150" align="center" />
-                    <el-table-column prop="size" label="空间大小" width="100" align="center" />
-                    <el-table-column prop="region" label="国家" width="100" align="center" />
-                    <el-table-column prop="province" label="省" width="100" align="center" />
-                    <el-table-column prop="city" label="市" width="100" align="center" />
-                    <el-table-column prop="dist" label="区" width="100" align="center" />
-                    <el-table-column prop="address" label="详细地址" width="250" align="center" />
+                    <el-table-column prop="index" label="编号" type=index align="center" />
+                    <el-table-column prop="name" label="名称" align="center" />
+                    <el-table-column prop="admin" label="管理关联账号" align="center" />
+                    <el-table-column prop="period" label="学段" align="center" />
+                    <el-table-column prop="size" label="空间大小" align="center" />
+                    <el-table-column prop="region" label="国家" align="center" />
+                    <el-table-column prop="province" label="省" align="center" />
+                    <el-table-column prop="city" label="市" align="center" />
+                    <el-table-column prop="dist" label="区" align="center" />
+                    <el-table-column prop="address" label="详细地址" align="center" />
                 </el-table>
                 <div class="batchs-btn">
                     <el-button type="primary" size="medium" @click="quantity();createdSchoolLoading=true" :loading="createdSchoolLoading">批量建立学校</el-button>
@@ -736,7 +736,7 @@ export default {
     background: url('../../assets/img/list-num.png');
 }
 .add-schoolbtn {
-    width: 5.5%;
+    width: 9%;
     line-height: 0px;
 }
 .add-schoolbtn button {
@@ -767,6 +767,7 @@ export default {
     overflow: hidden;
     margin-right: 5px;
     line-height: 6em;
+    margin-top: 10%;
 }
 .textandbtn p {
     font-size: 15px;

+ 1 - 1
TEAMModeBI/ClientApp/src/view/home.vue

@@ -1,6 +1,6 @@
 <template>
     <div class="common-layout viewbox">
-        <el-container style="height: 100vh; border: 1px solid #eee">
+        <el-container style="height: 100vh">
             <Aside></Aside>
             <el-container>
                 <el-header>

+ 4 - 3
TEAMModeBI/ClientApp/src/view/index/dashboard.vue

@@ -398,7 +398,7 @@ ul > li {
 /*头部样式*/
 .headers {
     position: relative;
-    height: 6.25rem;
+    height: 11vh;
     background: url('../../assets/img/dashboard-head_bg.png') no-repeat;
     background-size: 100% 100%;
 }
@@ -430,6 +430,7 @@ ul > li {
     flex: 5;
     margin: 0 1.125rem 1.1875rem;
     overflow: hidden;
+    min-height: 88vh;
 }
 .mainBox .column .panel {
     position: relative;
@@ -458,7 +459,7 @@ ul > li {
     font-weight: 400;
 }
 .mainBox .column .panel .chart {
-    height: 15rem;
+    height: 25vh;
 }
 .mainBox .column .panel .panel-footer {
     position: absolute;
@@ -562,7 +563,7 @@ ul > li {
     top: 0;
     left: 0;
     z-index: 5;
-    height: 41.5rem;
+    height: 68vh;
     width: 100%;
 }
 .mainBox .column-center .map .map1 {

+ 12 - 11
TEAMModeBI/ClientApp/src/view/teachermanage/areamanage.vue

@@ -19,15 +19,15 @@
             </div>
         </div>
         <div class="traitfrom">
-            <el-table :data="optionData" style="width: 100%" :highlight-current-row="true" height="77vh" v-loading="loading">
-                <el-table-column prop="index" label="编号" width="200" type=index sortable align="center" />
-                <el-table-column prop="name" label="名称" width="200" align="center" />
-                <el-table-column prop="id" label="ID编码" width="200" align="center" />
-                <el-table-column prop="provName" label="省份" width="200" align="center" />
-                <el-table-column prop="cityName" label="城市" width="200" align="center" />
-                <el-table-column prop="institution" label="所属机构" width="250" align="center" />
-                <el-table-column prop="standardName" label="微能力点方案" width="200" align="center" />
-                <el-table-column label="操作" width="150" align="center" v-if="PowerShow">
+            <el-table :data="optionData" style="width: 100%" :highlight-current-row="true" height="74vh" v-loading="loading">
+                <el-table-column prop="index" label="编号" type=index sortable align="center" />
+                <el-table-column prop="name" label="名称" align="center" />
+                <el-table-column prop="id" label="ID编码" align="center" />
+                <el-table-column prop="provName" label="省份" align="center" />
+                <el-table-column prop="cityName" label="城市" align="center" />
+                <el-table-column prop="institution" label="所属机构" align="center" />
+                <el-table-column prop="standardName" label="微能力点方案" align="center" />
+                <el-table-column label="操作" align="center" v-if="PowerShow">
                     <template #default="scope">
                         <el-button size="mini" @click="operation(scope.$index, scope.row,true)">操作</el-button>
                     </template>
@@ -317,6 +317,7 @@ export default {
             changeStyle,
             PowerShow,
             deleteRow,
+            loading,
         }
     },
 }
@@ -499,10 +500,10 @@ export default {
     display: block;
 }
 .list-school-logo {
-    width: 17%;
+    width: 20%;
 }
 .list-school-name {
-    width: 55%;
+    width: 65%;
     padding-left: 1%;
 }
 .list-school-name div {

+ 9 - 9
TEAMModeBI/ClientApp/src/view/teachermanage/manage.vue

@@ -14,9 +14,9 @@
         </el-button>
     </div>
     <div class="manage-table">
-        <el-table :data="tableData.value" style="width: 100%" height="85vh" v-loading="loading" element-loading-text="Loading..." class="customer-table">
-            <el-table-column prop="id" label="编号" width="100" sortable align="center" />
-            <el-table-column label="头像" width="200" align="center">
+        <el-table :data="tableData.value" style="width: 100%" height="80vh" v-loading="loading" element-loading-text="Loading..." class="customer-table">
+            <el-table-column prop="id" label="编号" sortable align="center" />
+            <el-table-column label="头像" align="center">
                 <template #default="scope">
                     <el-image style="width: 70px; height: 70px;border-radius:50%" :src="scope.row.avatar" fit="fill" v-if="scope.row.avatar !=='' "></el-image>
                     <div v-if="scope.row.avatar ===''">
@@ -26,9 +26,9 @@
                     </div>
                 </template>
             </el-table-column>
-            <el-table-column prop="name" label="姓名" width="250" sortable align="center" />
+            <el-table-column prop="name" label="姓名" sortable align="center" />
             <!-- <el-table-column prop="isexist" label="状态" width="250" align="center" /> -->
-            <el-table-column prop="isexist" label="状态" width="300" align="center">
+            <el-table-column prop="isexist" label="状态" align="center">
                 <template #default="scope">
                     <svg class="icon-table" aria-hidden="true" v-if="scope.row.userstate ===false">
                         <use xlink:href="#icon-jihuoma"></use>
@@ -49,9 +49,9 @@
                     </el-popover>
                 </template>
             </el-table-column>
-            <el-table-column prop="mobile" label="电话" width="300" align="center" />
-            <el-table-column prop="title" label="职位" width="200" sortable align="center" />
-            <el-table-column label="操作" width="300" align="center">
+            <el-table-column prop="mobile" label="电话" align="center" />
+            <el-table-column prop="title" label="职位" sortable align="center" />
+            <el-table-column label="操作" align="center">
                 <template #default="scope">
                     <el-button type="primary" icon="el-icon-edit" @click="handleClick(scope.$index,tableData)">查看/编辑</el-button>
                 </template>
@@ -59,7 +59,7 @@
         </el-table>
     </div>
     <div class="manatips">
-        <el-dialog v-model="managebox" title="权限管理" width="30%">
+        <el-dialog v-model="managebox" title="权限管理" width="40%">
             <div class="manageboxs">
                 <div class="manatips-box" v-for="item in manageList">
                     <div class="manatips-name">{{item.name}}</div>

+ 17 - 17
TEAMModeBI/ClientApp/src/view/teachermanage/school.vue

@@ -18,7 +18,7 @@
             </div>
             <div class="dist-box">
                 <span>区域:</span>
-                <el-select v-model="distOptions.distValue" filterable="true" allow-create default-first-option placeholder="区域选择" @change="areaSelctChange(distOptions.distValue,'dist')">
+                <el-select v-model="distOptions.distValue" filterable allow-create default-first-option placeholder="区域选择" @change="areaSelctChange(distOptions.distValue,'dist')">
                     <el-option v-for="item in distOptions.distInfo" :key="item.code" :label="item.name" :value="item.name">
                     </el-option>
                 </el-select>
@@ -41,32 +41,32 @@
             </a>
         </div>
         <div class="school-list">
-            <el-table :data="tableData" style="width: 100%" heigt="80vh" v-loading="loading" element-loading-text="加载中...">
-                <el-table-column prop="index" label="编号" width="80" type="index" sortable align="center" />
+            <el-table :data="tableData" style="width: 100%" height="75vh" v-loading="loading" element-loading-text="加载中...">
+                <el-table-column prop="index" label="编号" type="index" sortable align="center" />
                 <el-table-column label="头像" width="150" align="center">
                     <template #default="scope">
                         <el-image style="width: 70px; height: 70px" :src="scope.row.picture" fit="fill"></el-image>
                     </template>
                 </el-table-column>
-                <el-table-column prop="name" label="名称" width="220" sortable align="center" />
+                <el-table-column prop="name" label="名称" sortable align="center" />
                 <!-- <el-table-column label="学段" width="150" align="center">
                     <template #default="scope">
                         <span>{{scope.row.period[0].name}}</span>
                     </template>
                 </el-table-column> -->
-                <el-table-column prop="id" label="学校简码" width="150" align="center" />
-                <el-table-column prop="province" label="省" width="150" align="center" />
-                <el-table-column prop="city" label="市" width="150" align="center" />
-                <el-table-column prop="dist" label="区" width="150" align="center" />
-                <el-table-column prop="size" label="空间容量" width="150" align="center" />
-                <el-table-column label="关联管家" width="200" align="center">
+                <el-table-column prop="id" label="学校简码" align="center" />
+                <el-table-column prop="province" label="省" align="center" />
+                <el-table-column prop="city" label="市" align="center" />
+                <el-table-column prop="dist" label="区" align="center" />
+                <el-table-column prop="size" label="空间容量" align="center" />
+                <el-table-column label="关联管家" align="center">
                     <template #default="scope">
                         <div v-if="scope.row.assisName">{{scope.row.assisName}}</div>
                         <div v-else>暂无</div>
                     </template>
                 </el-table-column>
                 <!-- <el-table-column prop="state" label="状态" width="110" align="center" /> -->
-                <el-table-column label="操作" width="200" align="center" v-if="PowerShow">
+                <el-table-column label="操作" align="center" v-if="PowerShow">
                     <template #default="scope">
                         <el-button type="text" size="small" @click.prevent="deleteRow(scope.$index, scope.row)">编辑</el-button>
                     </template>
@@ -86,7 +86,7 @@
                     <el-input v-model="nowPitchdata.name"></el-input>
                 </el-form-item>
                 <el-form-item label="校徽:" class="school-form-badge">
-                    <el-upload class="upload-demo" :headers="uploadHeader" action="/blob/upload-public" :before-upload="changeBadge" :on-exceed="handleExceed" :on-success="success" :on-error="handleUpdErr">
+                    <el-upload class="upload-demo" :headers="uploadHeader" action="/blob/upload-public" :before-upload="changeBadge" :on-success="success" :on-error="handleUpdErr">
                         <el-image style="width: 125px; height:125px" :src="nowPitchdata.picture" fit="contain"></el-image>
                         <div class="changebadge">
                             <el-button>更 换</el-button>
@@ -535,14 +535,14 @@ export default {
 }
 .school-form-badge,
 .school-form-code {
-    width: 18%;
+    width: 24%;
 }
 .school-form-grading {
-    width: 45%;
+    width: 80%;
 }
 .changebadge {
-    width: 100%;
-    height: 100%;
+    width: 125px;
+    height: 125px;
     position: absolute;
     top: 0px;
     left: 0px;
@@ -555,7 +555,7 @@ export default {
     width: 21%;
 }
 .school-form-admin {
-    width: 30%;
+    width: 35%;
     text-align: left;
 }
 .school-form-state {

+ 22 - 23
TEAMModeBI/ClientApp/src/view/teachermanage/traitmanage.vue

@@ -9,7 +9,7 @@
                             <div class="card-number">{{index+1}}</div>
                             <template #header>
                                 <div class="card-header">
-                                    <span>{{item.standardName}}</span>
+                                    <span class="card-names" :title="item.standardName">{{item.standardName}}</span>
                                     <el-button class="button" type="text" @click="pitch(item)" v-if="PowerShow">编辑</el-button>
                                 </div>
                             </template>
@@ -413,9 +413,9 @@ export default {
         let addTask = ref(false)
         let taskModel = ref('')
         let taskFormLabel = ref({
-            id: guid(),
+            id: proxy.$access.guid(),
             std: '',
-            task: [{ id: guid(), stddesc: '', titles: [], score: [], type: [] }],
+            task: [{ id: proxy.$access.guid(), stddesc: '', titles: [], score: [], type: [] }],
         })
         //提交类型
         let submitType = [
@@ -484,13 +484,16 @@ export default {
                         element.name === '信息化能力工程2.0通识性课程' ? (element.no = '通用') : ''
                     })
                 }
-                // if (res.abilities.length === 0) {
-                //     ElMessage.error('该方案数据异常或为空,无法访问')
-                //     return
-                // }
+                if (res.abilities.length === 0) {
+                    ElMessage.error('该方案数据异常,无法访问')
+                    return
+                }
                 res.abilities.sort(function (s, t) {
                     var a = s.no.toLowerCase()
                     var b = t.no.toLowerCase()
+                    if (a === '通用' || b === '通用') {
+                        return -1
+                    }
                     if (a.length === 2) {
                         a = a.slice(0, a.length - 1) + '0' + a.slice(-1)
                     }
@@ -703,18 +706,18 @@ export default {
             let operates = operate
             let criterions = criterion
             console.log(taskFormLabel, '123456')
-            operates === 'add' && criterions === 'excellent' ? taskFormLabel.value.task[0].titles.push({ id: guid(), title: '', value: '1' }) : ''
-            operates === 'add' && criterions === 'qualified' ? taskFormLabel.value.task[0].score.push({ id: guid(), title: '', value: '2' }) : ''
+            operates === 'add' && criterions === 'excellent' ? taskFormLabel.value.task[0].titles.push({ id: proxy.$access.guid(), title: '', value: '1' }) : ''
+            operates === 'add' && criterions === 'qualified' ? taskFormLabel.value.task[0].score.push({ id: proxy.$access.guid(), title: '', value: '2' }) : ''
             if (operates === 'del' && criterions === 'excellent') {
                 let num = ''
                 for (let i in taskFormLabel.value.task[0].titles) {
-                    taskFormLabel.value.task[0].titles[i].id === id ? (num = id) : ''
+                    taskFormLabel.value.task[0].titles[i].id === id ? (num = i) : ''
                 }
                 taskFormLabel.value.task[0].titles.splice(num, 1)
             } else if (operates === 'del' && criterions === 'qualified') {
                 let num = ''
                 for (let i in taskFormLabel.value.task[0].score) {
-                    taskFormLabel.value.task[0].score[i].id === id ? (num = id) : ''
+                    taskFormLabel.value.task[0].score[i].id === id ? (num = i) : ''
                 }
                 taskFormLabel.value.task[0].score.splice(num, 1)
             }
@@ -738,14 +741,6 @@ export default {
             addTask.value = false
             console.log(data, newData, '处理过后的')
         }
-        //GUID生成
-        function guid() {
-            return randomId() + randomId() + '-' + randomId() + '-' + randomId() + '-' + randomId() + '-' + randomId() + randomId() + randomId()
-        }
-        // 生成随机UUID工具
-        function randomId() {
-            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
-        }
         onMounted(() => {
             console.log(store.state.point.length)
             store.state.point.length
@@ -787,8 +782,6 @@ export default {
             onSaveCompulsory,
             idBtnLoading,
             treeDataInfo,
-            guid,
-            randomId,
             nowVolumeName,
             redactSaveAbility,
             redactSaveloading,
@@ -877,7 +870,7 @@ export default {
 }
 .ability-box {
     width: 337px;
-    height: 88vh;
+    height: 85vh;
     border-right: 1px dashed rgb (180, 178, 178);
     margin-top: 30px;
     margin-left: -5%;
@@ -1222,6 +1215,11 @@ export default {
 .abilitysInfo {
     line-height: 60px;
 }
+.card-names {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
 </style>
 <style>
 .box-card .el-card__header,
@@ -1235,8 +1233,9 @@ export default {
     width: 100%;
 }
 .allbox .el-tabs__content {
-    min-height: 800px;
+    height: 80vh;
     text-align: left;
+    overflow-y: auto;
 }
 .ability-box {
     line-height: 20px;

+ 14 - 55
TEAMModeBI/Controllers/BIAbility/AbilityMgmtController.cs

@@ -15,6 +15,7 @@ using HTEXLib.COMM.Helpers;
 using System.Text;
 using TEAMModelOS.SDK.Models.Cosmos.BI;
 using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Helper.Common.TableHelper;
 
 namespace TEAMModeBI.Controllers.BIAbility
 {
@@ -31,9 +32,10 @@ namespace TEAMModeBI.Controllers.BIAbility
         private readonly Option _option;
 
         private readonly AzureStorageFactory _azureStorage;
-
+        public readonly string mobel = "册别";
         public AbilityMgmtController(IConfiguration configuration, AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage)
         {
+            _configuration = configuration;
             _azureCosmos = azureCosmos;
             _dingDing = dingDing;
             _option = option?.Value;
@@ -113,23 +115,6 @@ namespace TEAMModeBI.Controllers.BIAbility
                     return Ok(new { state = 0,message= "standard 参数异常" });
                 }
 
-                //操作记录
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog operateLog = new OperateLog
-                {
-                    PartitionKey = "OperateLog-BI",
-                    RowKey = blobOrTable,
-                    recordID = blobOrTable,
-                    platformSource = "BI",
-                    tmdId = $"{_tmdId}",
-                    tmdName = $"{_tmdName}",
-                    visitApi = "/biabilitymgmt/del-ability",
-                    operateTime = DateTime.Now,
-                    operateType = "删除",
-                    funModule = "册别",
-                    operateDescribe = $"{_tmdName}【{_tmdId}】已操作删除册别,删除ID:{id}"
-                };
-
                 var client = _azureCosmos.GetCosmosClient();
                 List<AbilityTask> syllabus = new List<AbilityTask>();
                 string sql = $"select value(c) from c where c.abilityId='{id}'";
@@ -145,7 +130,9 @@ namespace TEAMModeBI.Controllers.BIAbility
 
                 if (response.Status == 200)
                 {
-                    await _azureStorage.Save<OperateLog>(operateLog);
+                    //保存操作记录
+                    await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdName}【{_tmdId}】已操作删除册别,删除ID:{id}", type: "ability-del", visitApi: "/biabilitymgmt/del-ability", funModel: mobel);
+
                     return Ok(new { state = 200 });
                 }
                 else return Ok(new { state = response.Status });
@@ -167,16 +154,6 @@ namespace TEAMModeBI.Controllers.BIAbility
         {
             try
             {
-                //操作记录
-                OperateLog operateLog = new OperateLog();
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{recordAbility.tmdId}";
-                operateLog.tmdName = $"{recordAbility.tmdName}";
                 StringBuilder stringBuilder = new StringBuilder($"{recordAbility.tmdName}【{recordAbility.tmdId}】已操作");
 
                 Ability ability = recordAbility.ability;
@@ -192,7 +169,7 @@ namespace TEAMModeBI.Controllers.BIAbility
                 else return Ok(new { state = 0, message = "参数异常" });
 
                 var azureClient = _azureCosmos.GetCosmosClient();
-
+                string tempType = "";
                 //新增册别
                 if (string.IsNullOrEmpty(ability.id))
                 {
@@ -216,13 +193,11 @@ namespace TEAMModeBI.Controllers.BIAbility
                     {
                         return Ok(new { sate = 2, mesages = "参数异常" });
                     }
-
+                    tempType = "ability-add";
                     ability.id = Guid.NewGuid().ToString();
                     ability.creatorId = string.IsNullOrEmpty($"{ability.creatorId}") ?$"{recordAbility.tmdId}": ability.creatorId;
                     ability.creatorName = string.IsNullOrEmpty($"{ability.creatorName}") ? $"{recordAbility.tmdName}" : ability.creatorName;
                     tempAbility = await azureClient.GetContainer("TEAMModelOS", "Normal").CreateItemAsync(ability, new PartitionKey(ability.code));
-                    operateLog.operateType = "新增";
-                    operateLog.funModule = "册别";
                     stringBuilder.Append($"新增册别信息,册别编号:{tempAbility.id},册别名称:{tempAbility.name}");
                 }
                 //更新册别
@@ -231,9 +206,8 @@ namespace TEAMModeBI.Controllers.BIAbility
                     try
                     {
                         tempAbility = await azureClient.GetContainer(Constant.TEAMModelOS, "Normal").ReplaceItemAsync<Ability>(ability, ability.id, new PartitionKey(ability.code));
-                        operateLog.operateType = "修改";
-                        operateLog.funModule = "册别";
                         stringBuilder.Append($"更新册别信息,册别编号:{tempAbility.id},册别名称:{tempAbility.name}");
+                        tempType = "ability-update";
 
                     }
                     catch (Exception ex)
@@ -243,10 +217,8 @@ namespace TEAMModeBI.Controllers.BIAbility
                     }
                 }
 
-                operateLog.operateDescribe = $"{stringBuilder}";
-                operateLog.visitApi = "/biabilitymgmt/upd-ability";
-                operateLog.operateTime = DateTime.Now;
-                await _azureStorage.Save<OperateLog>(operateLog);
+                //保存操作记录
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform:"BI", tmdId:$"{recordAbility.tmdId}", tmdName:$"{recordAbility.tmdName}", msg: stringBuilder?.ToString(), type: tempType?.ToString(), visitApi: "/biabilitymgmt/upd-ability", funModel: mobel);
 
                 return Ok(new { state = 200, Ability = tempAbility });
             }
@@ -275,20 +247,6 @@ namespace TEAMModeBI.Controllers.BIAbility
 
                 //操作记录
                 string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog operateLog = new OperateLog
-                {
-                    PartitionKey = "OperateLog-BI",
-                    RowKey = blobOrTable,
-                    recordID = blobOrTable,
-                    platformSource = "BI",
-                    tmdId = $"{_tmdId}",
-                    tmdName = $"{_tmdName}",
-                    operateType="修改",
-                    funModule="册别",
-                    visitApi = "/biabilitymgmt/upd-isrequired",
-                    operateTime = DateTime.Now,
-                    operateDescribe = $"{_tmdName}【{_tmdId}】已操作设置是否必修状态。标准:{currencys[0].standard}"
-                };
 
                 foreach (var item in currencys)
                 {
@@ -298,12 +256,13 @@ namespace TEAMModeBI.Controllers.BIAbility
                     await cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").ReplaceItemAsync(ability, ability.id, new PartitionKey(ability.code));
                 }
 
-                await _azureStorage.Save<OperateLog>(operateLog);
+                //保存操作记录
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdName}【{_tmdId}】已操作设置是否必修状态。标准:{currencys[0].standard}",type:"ability-update", visitApi: "/biabilitymgmt/upd-isrequired", funModel: mobel);
                 return Ok(new { state = 200, currencys });
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"BI,{_option.Location}  /biabilitymgmt/upd-isrequired    \n  {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
+                await _dingDing.SendBotMsg($"BI,{_option.Location}  /biabilitymgmt/upd-isrequired  \n  {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
                 return BadRequest();
             }
         }

+ 16 - 40
TEAMModeBI/Controllers/BIAbility/AbilityTaskMgmtController.cs

@@ -15,6 +15,8 @@ using HTEXLib.COMM.Helpers;
 using TEAMModelOS.Services.Common;
 using TEAMModelOS.SDK.Models.Cosmos.BI;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
+using TEAMModelOS.SDK.Helper.Common.TableHelper;
+using System.Text;
 
 namespace TEAMModeBI.Controllers.BIAbility
 {
@@ -31,9 +33,11 @@ namespace TEAMModeBI.Controllers.BIAbility
         //钉钉提示信息
         private readonly DingDing _dingDing;
         private readonly Option _option;
+        public readonly string mobel = "章节";
 
         public AbilityTaskMgmtController(IConfiguration configuration, AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage)
         {
+            _configuration = configuration;
             _azureCosmos = azureCosmos;
             _dingDing = dingDing;
             _option = option?.Value;
@@ -120,18 +124,9 @@ namespace TEAMModeBI.Controllers.BIAbility
             try
             {
                 var cosmosClient = _azureCosmos.GetCosmosClient();
-                //操作记录
-                OperateLog operateLog = new OperateLog();
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{recordAbilityTask.tmdId}";
-                operateLog.tmdName = $"{recordAbilityTask.tmdName}";
-                operateLog.visitApi = "/biabilitytask/upd-abilitytask";
 
+                StringBuilder msgBuilder = new StringBuilder($"{recordAbilityTask.tmdName}【{recordAbilityTask.tmdId}】已操作");
+                string type = null;
                 long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                 foreach (var abilityTaskTree in recordAbilityTask.abilityTask)
                 {
@@ -178,11 +173,8 @@ namespace TEAMModeBI.Controllers.BIAbility
                             abilityTaskTree.auth = abilityTask.auth;
                             await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Normal").ReplaceItemAsync<AbilityTask>(abilityTask, abilityTask.id, new Azure.Cosmos.PartitionKey($"AbilityTask-{recordAbilityTask.standard}"));
                         }
-
-                        operateLog.operateType = "修改";
-                        operateLog.funModule = "章节";
-                        operateLog.operateDescribe = $"{recordAbilityTask.tmdName}【{recordAbilityTask.tmdId}】已操作修改章节功能,章节ID和分区键{abilityTask.id}And{abilityTask.code} ";
-                        operateLog.operateTime = DateTime.Now;
+                        msgBuilder.Append($"修改章节功能,章节ID:{abilityTask.id} 分区键:{abilityTask.code}");
+                        type = "abilityTask-update";
                     }
                     else
                     {
@@ -208,14 +200,13 @@ namespace TEAMModeBI.Controllers.BIAbility
                         };
                         await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Normal").CreateItemAsync<AbilityTask>(abilityTask, new Azure.Cosmos.PartitionKey($"AbilityTask-{recordAbilityTask.standard}"));
 
-                        operateLog.operateType = "新增";
-                        operateLog.funModule = "章节";
-                        operateLog.operateDescribe = $"{recordAbilityTask.tmdName}【{recordAbilityTask.tmdId}】已操作新增章节功能,章节ID和分区键{abilityTask.id}And{abilityTask.code} ";
-                        operateLog.operateTime = DateTime.Now;
+                        msgBuilder.Append($"修改章节功能,章节ID:{abilityTask.id} 分区键:{abilityTask.code}");
+                        type = "abilityTask-add";
                     }
                 }
 
-                await _azureStorage.Save<OperateLog>(operateLog);
+                //保存操作日志
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{recordAbilityTask.tmdId}", tmdName: $"{recordAbilityTask.tmdName}", msg: msgBuilder?.ToString(), type: type?.ToString(), visitApi: "/biabilitytask/upd-abilitytask", funModel: mobel);
 
                 return Ok(new { state = 200, recordAbilityTask });
             }
@@ -241,28 +232,13 @@ namespace TEAMModeBI.Controllers.BIAbility
                 if (!jsonElement.TryGetProperty("id", out JsonElement id)) return BadRequest();
                 if (!jsonElement.TryGetProperty("tmdId", out JsonElement _tmdId)) return BadRequest();   //醍摩豆账户
                 if (!jsonElement.TryGetProperty("tmdName", out JsonElement _tmdName)) return BadRequest(); //醍摩豆账号名称
-
-                //操作记录
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog operateLog = new OperateLog
-                {
-                    PartitionKey = "OperateLog-BI",
-                    RowKey = blobOrTable,
-                    recordID = blobOrTable,
-                    platformSource = "BI",
-                    tmdId = $"{_tmdId}",
-                    tmdName = $"{_tmdName}",
-                    operateType = "删除",
-                    funModule = "章节",
-                    visitApi = "/biabilitytask/delabilitytask",
-                    operateTime = DateTime.Now
-                };
-
+                
                 var cosmosClient = _azureCosmos.GetCosmosClient();
                 var response = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").DeleteItemStreamAsync(id.ToString(), new PartitionKey($"AbilityTask-{standard}"));
 
-                operateLog.operateDescribe = $"{_tmdName}【{_tmdId}】已操作删除册别,删除状态:{response.Status},删除ID:{id}";
-                await _azureStorage.Save<OperateLog>(operateLog);//保存操作记录
+                //保存操作日志
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdName}【{_tmdId}】已操作删除册别,删除状态:{response.Status},删除ID:{id}", type: "abilitytask-del", visitApi: "/biabilitytask/del-abilitytask", funModel: mobel);
+
                 if (response.Status == 204)
                     return Ok(new { state = 200 });
                 else

+ 12 - 11
TEAMModeBI/Controllers/BIHome/HomeStatisController.cs

@@ -1057,17 +1057,18 @@ namespace TEAMModeBI.Controllers.BIHome
                         //    sizeS += tempSize;
                         //}
                     }
-                    //else
-                    //{
-                    //    var client = _azureStorage.GetBlobContainerClient(itemId);
-                    //    var size = await client.GetBlobsCatalogSize();
-                    //    var temp = await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", itemId, size.Item1);
-                    //    foreach (var itemKey in size.Item2.Keys)
-                    //    {
-                    //        var temp1 = await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{itemId}", itemKey);
-                    //        var temp2 = await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{itemId}", itemKey, size.Item2[itemKey].HasValue ? size.Item2[itemKey].Value : 0);
-                    //    }
-                    //}
+                    else
+                    {
+                        var client = _azureStorage.GetBlobContainerClient(itemId);
+                        var size = await client.GetBlobsCatalogSize();
+                        var temp = await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", itemId, size.Item1);
+                        foreach (var itemKey in size.Item2.Keys)
+                        {
+                            var temp1 = await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{itemId}", itemKey);
+                            var temp2 = await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{itemId}", itemKey, size.Item2[itemKey].HasValue ? size.Item2[itemKey].Value : 0);
+                            sizeS += Convert.ToInt64(temp2);
+                        }
+                    }
 
                     SortedSetEntry[] sortedSetEntries = await _azureRedis.GetRedisClient(8).SortedSetRangeByRankWithScoresAsync($"Blob:Catalog:{itemId}");
                     if (sortedSetEntries != null)

+ 7 - 14
TEAMModeBI/Controllers/BISchool/AreaRelevantController.cs

@@ -11,6 +11,7 @@ using TEAMModeBI.Filter;
 using TEAMModelOS.Models;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Helper.Common.TableHelper;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos.BI;
 
@@ -22,11 +23,13 @@ namespace TEAMModeBI.Controllers.BISchool
     {
         //数据容器
         private readonly AzureCosmosFactory _azureCosmos;
+        private readonly AzureStorageFactory _azureStorage;
         //钉钉提示信息
         private readonly DingDing _dingDing;
         private readonly Option _option;
+        public readonly string mobel = "区级";
 
-        public AreaRelevantController(AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option)
+        public AreaRelevantController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, DingDing dingDing, IOptionsSnapshot<Option> option)
         {
             _azureCosmos = azureCosmos;
             _dingDing = dingDing;
@@ -97,19 +100,6 @@ namespace TEAMModeBI.Controllers.BISchool
                 //if (!jsonElement.TryGetProperty("areaId", out JsonElement areaId)) return BadRequest();
                 if (!jsonElement.TryGetProperty("schoolId", out JsonElement schoolId)) return BadRequest();
 
-                //操作记录
-                OperateLog operateLog = new OperateLog();
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{_tmdId}";
-                operateLog.tmdName = $"{_tmdName}";
-                operateLog.visitApi = "/tabledd/set-permissions";
-                operateLog.operateTime = DateTime.Now;
-                operateLog.operateDescribe = $"{_tmdName}【{_tmdId}】已操作学校({schoolId})移除该区域";
-
                 var cosmosClient = _azureCosmos.GetCosmosClient();
                 School tempSchool = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{schoolId}", new PartitionKey("Base"));
 
@@ -118,6 +108,9 @@ namespace TEAMModeBI.Controllers.BISchool
 
                 School school = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<School>(tempSchool, tempSchool.id, new PartitionKey("Base"));
 
+                //保存操作日志
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdName}【{_tmdId}】已操作学校({schoolId})移除该区域", type: "area-update", visitApi: "/area/set-areashiftschool", funModel: mobel);
+
                 return Ok(new { state = 200, school });
             }
             catch (Exception ex)

+ 8 - 220
TEAMModeBI/Controllers/BISchool/BatchAreaController.cs

@@ -27,6 +27,7 @@ using TEAMModelOS.SDK.Models.Cosmos.BI;
 using Azure.Messaging.ServiceBus;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models.Service;
+using TEAMModelOS.SDK.Helper.Common.TableHelper;
 
 namespace TEAMModeBI.Controllers.BISchool
 {
@@ -163,22 +164,7 @@ namespace TEAMModeBI.Controllers.BISchool
 
                 //操作记录实体
                 var tempStandard = !string.IsNullOrEmpty($"{oldStandard}") && !string.IsNullOrEmpty($"{_oldId}") ? $"{oldStandard}" : "standard2";
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog bIOperateLog = new OperateLog
-                {
-                    PartitionKey = "OperateLog-BI",
-                    RowKey = blobOrTable,
-                    recordID = blobOrTable,
-                    platformSource = "BI",
-                    tmdId = $"{_tmdId}",
-                    tmdName = $"{_tmdName}",
-                    operateType = "新增",
-                    funModule = "创区",
-                    operateDescribe = $"{_tmdName}【{_tmdId}】已操作创区功能模块:{name},当前标准【{standard}】,复制的微能力点:{tempStandard}",
-                    visitApi = "batcharea/batch-area",
-                    operateTime = DateTime.Now
-                };
-
+                
                 var cosmosClient = _azureCosmos.GetCosmosClient();//数据库连接
                 //查询新的是否存在
                 await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Area>(queryText: $"select value(c) from c where c.standard='{standard}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-Area") }))
@@ -470,8 +456,9 @@ namespace TEAMModeBI.Controllers.BISchool
                 var location = _option.Location;
                 await _notificationService.SendNotification(clientID, clientSecret, location, url, notification); //站内发送消息
 
-                //保存操作记录
-                await _azureStorage.Save<OperateLog>(bIOperateLog);
+                //保存操作日志
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdName}【{_tmdId}】已操作创区功能模块:{name},当前标准【{standard}】,复制的微能力点:{tempStandard}", type: "area-add", visitApi: "/batcharea/batch-area", funModel: "复制能力点");
+
                 return Ok(new { state = 200, area = addArea });
             }
             catch (Exception ex)
@@ -501,21 +488,7 @@ namespace TEAMModeBI.Controllers.BISchool
 
                 //操作记录实体
                 string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog bIOperateLog = new OperateLog
-                {
-                    PartitionKey = "OperateLog-BI",
-                    RowKey = blobOrTable,
-                    recordID = blobOrTable,
-                    platformSource = "BI",
-                    tmdId = $"{_tmdId}",
-                    tmdName = $"{_tmdName}",
-                    operateType ="修改",
-                    funModule ="能力点",
-                    operateDescribe = $"{_tmdName}【{_tmdId}】已操作【{_oldStandard}】切换至{_newStandard}微能力点,复制标准:{_newStandard}",
-                    visitApi = "/batcharea/cut-standard",
-                    operateTime = DateTime.Now
-                };
-
+                
                 var cosmosClient = _azureCosmos.GetCosmosClient();
 
                 List<string> abilityIds = new List<string>();  //册别的ID集合
@@ -670,7 +643,8 @@ namespace TEAMModeBI.Controllers.BISchool
                 await _notificationService.SendNotification(clientID, clientSecret, location, url, notification); //发送站内发送消息
 
                 //保存操作记录
-                await _azureStorage.Save<OperateLog>(bIOperateLog);
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdName}【{_tmdId}】已操作【{_oldStandard}】切换至{_newStandard}微能力点,复制标准:{_newStandard}", type: "standard-cut", visitApi: "/batcharea/cut-standard", funModel: "切换能力点");
+
                 return Ok(new { state = 200 });
             }
             catch (Exception ex)
@@ -680,192 +654,6 @@ namespace TEAMModeBI.Controllers.BISchool
             }
         }
 
-        #region  测试复制文件  流程通,后期删除
-
-        /// <summary>
-        /// 测试复制Blob中的文件  批量创区接口测试完成后删除
-        /// </summary>
-        /// <param name="jsonElement"></param>
-        /// <returns></returns>
-        [ProducesDefaultResponseType]
-        [HttpPost("copybolb")]
-        public async Task<IActionResult> TestCopyBolb(JsonElement jsonElement)
-        {
-            if (!jsonElement.TryGetProperty("cntr", out JsonElement _cntr)) return BadRequest();
-            if (!jsonElement.TryGetProperty("oldurl", out JsonElement _oldurl)) return BadRequest();
-            if (!jsonElement.TryGetProperty("newurl", out JsonElement _newurl)) return BadRequest();
-
-            var cosmosClient = _azureCosmos.GetCosmosClient();
-
-            int index = $"{_oldurl}".IndexOf("/", 0);
-            string oldUrl = index == 0 ? oldUrl = $"{_oldurl}".Substring(1) : oldUrl = $"{_oldurl}";
-
-            var bcc = _azureStorage.GetBlobContainerClient($"{_cntr}");  //获取地址
-
-            var urlSaS = _azureStorage.GetBlobSAS($"{_cntr}", oldUrl, BlobSasPermissions.Read | BlobSasPermissions.List);    // 取得容器sas 和有效期
-            //BlobBaseClient blob = new BlobBaseClient(new Uri(bcc.Uri+$"{setemp[0]}/{_newFile}"));     //新的地址
-            ////var s = blob.SyncCopyFromUri(new Uri(url));           //执行复制操作
-
-            var response = bcc.GetBlobClient($"{_newurl}").SyncCopyFromUri(new Uri(urlSaS));
-            if (response.Value.CopyStatus.Equals(1))
-                return Ok(new { state = 200, message = "复制成功" });
-            else return Ok(new { response.Value.CopyStatus });
-            //var response = await bcc.GetBlobClient($"{_newurl}").StartCopyFromUriAsync(new Uri(urlSaS));
-            //return Ok(new { state = 200 , response.Value,response.HasCompleted,response.HasValue,response.Id});
-        }
-
-        /// <summary>
-        /// 批量复制文件接口  批量创区接口测试完成后删除
-        /// </summary>
-        /// <param name="jsonElement"></param>
-        /// <returns></returns>
-        [ProducesDefaultResponseType]
-        [HttpPost("copybolbFile")]
-        public async Task<IActionResult> TestCopyBolbFile(JsonElement jsonElement)
-        {
-            if (!jsonElement.TryGetProperty("cntr", out JsonElement _cntr)) return BadRequest();
-            if (!jsonElement.TryGetProperty("oldstandard", out JsonElement _oldstandard)) return BadRequest();
-            if (!jsonElement.TryGetProperty("newstandard", out JsonElement _newstandard)) return BadRequest();
-
-            List<string> errmess = new List<string>();
-            List<string> fils = new List<string>();
-            List<Task<Response<BlobCopyInfo>>> file_list = new List<Task<Response<BlobCopyInfo>>>();
-            var client = _azureStorage.GetBlobContainerClient($"{_cntr}");//获取地址
-            await foreach (BlobItem item in client.GetBlobsAsync(BlobTraits.None, BlobStates.None, $"yxpt/{_oldstandard}/"))
-            {
-                fils.Add(item.Name);
-                string oldurl1 = $"{item.Name}".Replace($"/{_oldstandard}/", $"/{_newstandard}/");
-                var urlSaS = _azureStorage.GetBlobSAS($"{_cntr}", item.Name, BlobSasPermissions.Read | BlobSasPermissions.List);    // 取得容器sas 和有效期
-
-                client.GetBlobClient(oldurl1).SyncCopyFromUri(new Uri(urlSaS));
-                //file_list.Add(blobcc.GetBlobClient($"{oldurl1}").SyncCopyFromUriAsync(new Uri(urlSaS)));
-            }
-
-            if (file_list.Count <= 256)
-            {
-                await Task.WhenAll(file_list);
-            }
-            else
-            {
-                int pages = (file_list.Count + 255) / 256;
-                for (int i = 0; i < pages; i++)
-                {
-                    List<Task<Response<BlobCopyInfo>>> file_lists = file_list.Skip((i) * 256).Take(256).ToList();
-                    await Task.WhenAll(file_lists);
-                }
-            }
-
-            return Ok(new { fils.Count, fils });
-        }
-
-        /// <summary>
-        /// 批量删除在复制文件接口  正式完成后删除该接口
-        /// </summary>
-        /// <param name="jsonElement"></param>
-        /// <returns></returns>
-        [ProducesDefaultResponseType]
-        [HttpPost("copyafterdel")]
-        public async Task<IActionResult> CopyAfterDel(JsonElement jsonElement)
-        {
-
-            if (!jsonElement.TryGetProperty("cntr", out JsonElement _cntr)) return BadRequest();
-            if (!jsonElement.TryGetProperty("delstandard", out JsonElement _delstandard)) return BadRequest();
-            if (!jsonElement.TryGetProperty("copystandard", out JsonElement _copystandard)) return BadRequest();
-
-            var blobClient = _azureStorage.GetBlobContainerClient($"{_cntr}");  //获取地址
-
-            //先删除原有的文件
-            List<Task<Response<bool>>> DelList = new List<Task<Response<bool>>>();
-            await foreach (BlobItem blobItem in blobClient.GetBlobsAsync(BlobTraits.None, BlobStates.None, $"yxpt/{_delstandard}/"))
-            {
-                //await blobClient.GetBlobClient(blobItem.Name).DeleteIfExistsAsync();
-                DelList.Add(blobClient.GetBlobBaseClient(blobItem.Name).DeleteIfExistsAsync());
-            }
-
-            if (DelList.Count <= 256)
-            {
-                await Task.WhenAll(DelList);
-            }
-            else
-            {
-                int pages = (DelList.Count + 255) / 256;
-                for (int i = 0; i < pages; i++)
-                {
-                    List<Task<Response<bool>>> delList = DelList.Skip((i) * 256).Take(256).ToList();
-                    await Task.WhenAll(delList);
-                }
-            }
-
-            //在复制新的文件
-            List<Task<Response<BlobCopyInfo>>> CopyList = new List<Task<Response<BlobCopyInfo>>>();
-            await foreach (BlobItem blobItem in blobClient.GetBlobsAsync(BlobTraits.None, BlobStates.None, $"yxpt/{_copystandard}/"))
-            {
-                string oldurl = $"{blobItem.Name}".Replace($"/{_copystandard}/", $"/{_delstandard}/");  //替换旧文件
-                var copyUrlSas = _azureStorage.GetBlobSAS($"{_cntr}", blobItem.Name, BlobSasPermissions.Read | BlobSasPermissions.List);
-
-                //await blobClient.GetBlobClient(oldurl).SyncCopyFromUriAsync(new Uri(copyUrlSas));
-                CopyList.Add(blobClient.GetBlobClient(oldurl).SyncCopyFromUriAsync(new Uri(copyUrlSas)));
-            }
-
-            if (CopyList.Count <= 256)
-            {
-                await Task.WhenAll(CopyList);
-            }
-            else
-            {
-                int pages = (CopyList.Count + 255) / 256;
-                for (int i = 0; i < pages; i++)
-                {
-                    List<Task<Response<BlobCopyInfo>>> copyList = CopyList.Skip((i) * 256).Take(256).ToList();
-                    await Task.WhenAll(copyList);
-                }
-            }
-
-            return Ok(new { state = 200 });
-
-        }
-
-        /// <summary>
-        /// 批量复制文件夹方法   批量创区接口测试完成后删除
-        /// </summary>
-        /// <param name="_cntr"></param>
-        /// <param name="_oldstandard"></param>
-        /// <param name="_newstandard"></param>
-        /// <returns></returns>
-        public async Task<IActionResult> BarchCopyFile(string _cntr, string _oldstandard, string _newstandard)
-        {
-            List<string> errmess = new List<string>();
-            List<Task<Response<BlobCopyInfo>>> file_list = new List<Task<Response<BlobCopyInfo>>>();
-            var client = _azureStorage.GetBlobContainerClient($"{_cntr}");  //获取地址
-            await foreach (BlobItem item in client.GetBlobsAsync(BlobTraits.None, BlobStates.None, $"yxpt/{_oldstandard}/"))
-            {
-                string oldurl1 = $"{item.Name}".Replace($"/{_oldstandard}/", $"/{_newstandard}/");
-                //yxpt/standard6/jyzx/002ea332-0d1f-717c-0589-5f54c3c5ef4a/3 各班分数等级占比分析.mp4
-                var urlSaS = _azureStorage.GetBlobSAS($"{_cntr}", item.Name, BlobSasPermissions.Read | BlobSasPermissions.List);    // 取得容器sas 和有效期
-                //client.GetBlobClient($"{newurl}").SyncCopyFromUri(new Uri(urlSaS));
-                file_list.Add(client.GetBlobClient($"{oldurl1}").SyncCopyFromUriAsync(new Uri(urlSaS)));
-            }
-
-            if (file_list.Count <= 256)
-            {
-                await Task.WhenAll(file_list);
-            }
-            else
-            {
-                int pages = (file_list.Count + 255) / 256;
-                for (int i = 0; i < pages; i++)
-                {
-                    List<Task<Response<BlobCopyInfo>>> file_lists = file_list.Skip((i) * 256).Take(256).ToList();
-                    await Task.WhenAll(file_lists);
-                }
-            }
-
-            if (errmess.Count > 0) return Ok(new { state = 201, errmess });
-            else return Ok(new { state = 200, message = "全部复制成功" });
-        }
-
-        #endregion  
-
     }
 
 }

+ 74 - 131
TEAMModeBI/Controllers/BISchool/BatchSchoolController.cs

@@ -19,6 +19,11 @@ using static TEAMModelOS.SDK.Models.Teacher;
 using Microsoft.AspNetCore.Hosting;  //引用读取文件
 using TEAMModelOS.SDK.Models.Service;
 using System.IO;
+using TEAMModelOS.SDK.Helper.Common.TableHelper;
+using System.Net.Http;
+using Microsoft.Extensions.Configuration;
+using System.Net.Http.Json;
+using System.Net;
 
 namespace TEAMModeBI.Controllers.BISchool
 {
@@ -31,14 +36,20 @@ namespace TEAMModeBI.Controllers.BISchool
         private readonly Option _option;
         private readonly AzureStorageFactory _azureStorage;
         private readonly IWebHostEnvironment _environment; //读取文件
+        private readonly IHttpClientFactory _http;
+        //读取配置信息
+        private readonly IConfiguration _configuration;
+        public readonly string mobel = "学校";
 
-        public BatchSchoolController(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage, IOptionsSnapshot<Option> option, IWebHostEnvironment hostingEnvironment)
+        public BatchSchoolController(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage, IOptionsSnapshot<Option> option, IWebHostEnvironment hostingEnvironment, IConfiguration configuration, IHttpClientFactory http)
         {
             _azureCosmos = azureCosmos;
             _dingDing = dingDing;
             _azureStorage = azureStorage;
             _option = option?.Value;
             _environment = hostingEnvironment;
+            _configuration = configuration;
+            _http = http;
         }
 
         /// <summary>
@@ -124,19 +135,9 @@ namespace TEAMModeBI.Controllers.BISchool
                 if (!jsonElement.TryGetProperty("tmdName", out JsonElement _tmdName)) return BadRequest();
                 List<Exist> havepower = new List<Exist>(); //已存在的
                 var client = _azureCosmos.GetCosmosClient();
-                //保存操作记录
-                OperateLog operateLog = new OperateLog();
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{_tmdId}";
-                operateLog.tmdName = $"{_tmdName}";
-                operateLog.visitApi = "/batchschool/get-quitstaff";
-                operateLog.operateTime = DateTime.Now;
+
                 StringBuilder stringBuilder = new StringBuilder($"{_tmdName}【{_tmdId}】账户操作");
-                //更新
+                //更新权限
                 foreach (var id in ids.EnumerateArray())
                 {
                     SchoolTeacher st = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<SchoolTeacher>($"{id}", new PartitionKey($"Teacher-{school_code}"));
@@ -184,14 +185,14 @@ namespace TEAMModeBI.Controllers.BISchool
                     await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<SchoolTeacher>(st, id.GetString(), new PartitionKey($"Teacher-{school_code}"));
                 }
 
-                operateLog.operateDescribe = $"{stringBuilder}";
-                await _azureStorage.Save<OperateLog>(operateLog); //保存操作记录
+                //保存操作记录
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: stringBuilder?.ToString(), type: "ability-update", visitApi: "/batchschool/upd-permissions", funModel: mobel);
 
                 return Ok(new { state = 200, havepower = havepower });
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"BI,{_option.Location}, batchschool/get-quitstaff \n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
+                await _dingDing.SendBotMsg($"BI,{_option.Location}, /batchschool/upd-permissions \n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
                 return BadRequest();
             }
         }
@@ -208,17 +209,7 @@ namespace TEAMModeBI.Controllers.BISchool
             try
             {
                 List<BISchool> schools = new List<BISchool>();
-                //操作记录
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog operateLog = new OperateLog();
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{foundSchools.tmdId}";
-                operateLog.tmdName = $"{foundSchools.tmdName}";
-                operateLog.operateType = "新增";
-                operateLog.funModule = "创校";
+
                 StringBuilder stringBuilder = new StringBuilder($"{foundSchools.tmdName}【{foundSchools.tmdId}】操作了批量创校功能:");
 
                 if (foundSchools.biSchools.Count > 0)
@@ -226,6 +217,23 @@ namespace TEAMModeBI.Controllers.BISchool
                     var cosmosClient = _azureCosmos.GetCosmosClient();
                     foreach (BISchool bischool in foundSchools.biSchools)
                     {
+                        string tempTmdId = null;
+                        HttpClient httpClient = _http.CreateClient();
+                        string url = _configuration.GetValue<string>("HaBookAuth:CoreId:userinfo");
+                        List<string> mobile = new List<string>() { bischool.admin };
+                        HttpResponseMessage responseMessage = await httpClient.PostAsJsonAsync(url, mobile);
+                        if (responseMessage.StatusCode == HttpStatusCode.OK)
+                        {
+                            string temp = responseMessage.Content.ReadAsStringAsync().Result;
+                            List<JsonElement> json_id = temp.ToObject<List<JsonElement>>();
+                            foreach (var item in json_id)
+                            {
+                                tempTmdId = item.GetProperty("id").ToString();
+                            }
+                        }
+
+                        string tmdId = !string.IsNullOrEmpty(tempTmdId) ? tempTmdId : bischool.admin;
+
                         CreateSchoolInfo createSchoolInfo = new CreateSchoolInfo()
                         {
                             province = bischool.province,
@@ -276,7 +284,7 @@ namespace TEAMModeBI.Controllers.BISchool
                             try
                             {
                                 //查询该教师是否存在
-                                teacher = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>($"{bischool.admin}", new PartitionKey("Base"));
+                                teacher = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>($"{tmdId}", new PartitionKey("Base"));
                             }
                             catch
                             {
@@ -285,10 +293,10 @@ namespace TEAMModeBI.Controllers.BISchool
                             {
                                 //教师存在,在该教师信息中添加要管理的学校信息
                                 teacher.schools.Add(new Teacher.TeacherSchool { schoolId = createSchoolInfo.id, name = bischool.name, status = "join", time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() });
-                                //await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, bischool.admin, new PartitionKey("Base"));
+                                //await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, tmdId, new PartitionKey("Base"));
                                 SchoolTeacher schoolTeacher = new SchoolTeacher
                                 {
-                                    id = bischool.admin,
+                                    id = tmdId,
                                     code = $"Teacher-{createSchoolInfo.id}",
                                     roles = new List<string> { "admin", "teacher" },
                                     job = "管理员",
@@ -300,7 +308,7 @@ namespace TEAMModeBI.Controllers.BISchool
                                     ttl = -1
                                 };
 
-                                stringBuilder.Append($"教师信息:{schoolTeacher.name}【{schoolTeacher.id}】,教师权限:{schoolTeacher.roles.ToString()}");
+                                stringBuilder.Append($"教师信息:{schoolTeacher.name}【{schoolTeacher.id}】,教师权限:{string.Join(",", schoolTeacher.roles)}");
                                 await cosmosClient.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, teacher.id, new PartitionKey(teacher.code));
                                 await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync<SchoolTeacher>(schoolTeacher, new PartitionKey(schoolTeacher.code));
                             }
@@ -309,7 +317,7 @@ namespace TEAMModeBI.Controllers.BISchool
                                 //不存在 新建教师和新建要管理的学校信息
                                 Teacher addteacher = new Teacher
                                 {
-                                    id = bischool.admin,
+                                    id = tmdId,
                                     pk = "Base",
                                     code = "Base",
                                     name = $"{bischool.name}-管理员"?.ToString(),
@@ -324,11 +332,11 @@ namespace TEAMModeBI.Controllers.BISchool
                                 await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<Teacher>(addteacher, new PartitionKey("Base"));
                                 SchoolTeacher schoolTeacher = new SchoolTeacher
                                 {
-                                    id = bischool.admin,
+                                    id = tmdId,
                                     code = $"Teacher-{createSchoolInfo.id}",
                                     roles = new List<string> { "admin", "teacher" },
                                     job = "管理员",
-                                    name = bischool.admin,
+                                    name = $"{tmdId}-管理员",
                                     picture = "",
                                     status = "join",
                                     createTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
@@ -336,17 +344,16 @@ namespace TEAMModeBI.Controllers.BISchool
                                     ttl = -1
                                 };
 
-                                stringBuilder.Append($"教师权限:{schoolTeacher.roles}");
+                                stringBuilder.Append($"教师权限:{string.Join(",", schoolTeacher.roles)}");
                                 await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync<SchoolTeacher>(schoolTeacher, new PartitionKey(schoolTeacher.code));
                             }
                         }
                     }
                 }
                 else return Ok(new { state = 1, message = "创校信息为空" });
-                operateLog.operateDescribe = $"{stringBuilder}";
-                operateLog.visitApi = "/batchschool/batch-school";
-                operateLog.operateTime = DateTime.Now;
-                await _azureStorage.Save<OperateLog>(operateLog);
+
+                //保存操作记录
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{foundSchools.tmdId}", tmdName: $"{foundSchools.tmdName}", msg: stringBuilder?.ToString(), type: "school-batchAdd", visitApi: "/batchschool/batch-school", funModel: mobel);
 
                 if (schools.Count > 0)
                     return Ok(new { state = 201, message = "已有部分学校批量创建成功;学校编号已经重复!请检查学校编号!", schools = schools });
@@ -573,21 +580,8 @@ namespace TEAMModeBI.Controllers.BISchool
 
                     schoolInfo = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<School>(replaceSchool.school, replaceSchool.school.id, new PartitionKey("Base"));
 
-                    //操作记录
-                    string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                    OperateLog operateLog = new OperateLog
-                    {
-                        PartitionKey = "OperateLog-BI",
-                        RowKey = blobOrTable,
-                        recordID = blobOrTable,
-                        platformSource = "BI",
-                        tmdId = $"{replaceSchool.tmdId}",
-                        tmdName = $"{replaceSchool.tmdName}",
-                        operateDescribe = $"{replaceSchool.tmdName}【{replaceSchool.tmdId}】已操作修改学校,修改的学校:{replaceSchool.school.name}【{replaceSchool.school.id}】",
-                        visitApi = "/batchschool/upd-school",
-                        operateTime = DateTime.Now
-                    };
-                    await _azureStorage.Save<OperateLog>(operateLog);
+                    //保存操作记录
+                    await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{replaceSchool.tmdId}", tmdName: $"{replaceSchool.tmdName}", msg: $"{replaceSchool.tmdName}【{replaceSchool.tmdId}】已操作修改学校,修改的学校:{replaceSchool.school.name}【{replaceSchool.school.id}】", type: "school-update", visitApi: "/batchschool/upd-school", funModel: mobel);
 
                     return Ok(new { state = 200, schoolInfo });
                 }
@@ -627,19 +621,7 @@ namespace TEAMModeBI.Controllers.BISchool
 
                 //操作记录
                 string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog operateLog = new OperateLog
-                {
-                    PartitionKey = "OperateLog-BI",
-                    RowKey = blobOrTable,
-                    recordID = blobOrTable,
-                    platformSource = "BI",
-                    tmdId = $"{_tmdId}",
-                    tmdName = $"{_tmdName}",
-                    operateDescribe = $"{_tmdName}【{_tmdId}】已操作修改学校功能,修改的学校:{_schoolId},{string.Join("|", periodS.ToArray())},{picture},{size},{string.Join("|", assistId.ToArray())}",
-                    visitApi = "batchschool/upd-schoolassist",
-                    operateTime = DateTime.Now
-                };
-                await _azureStorage.Save<OperateLog>(operateLog);
+
 
                 var cosmosClient = _azureCosmos.GetCosmosClient();
                 School tempShool = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{_schoolId}", new PartitionKey("Base"));
@@ -774,6 +756,9 @@ namespace TEAMModeBI.Controllers.BISchool
                     schoolAssist.assists = assists;
                 }
 
+                //保存操作记录
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdName}【{_tmdId}】已操作修改学校功能,修改的学校:{_schoolId},{string.Join("|", periodS.ToArray())},{picture},{size},{string.Join("|", assistId.ToArray())}", type: "TeacherRoles-update", visitApi: "/batchschool/upd-schoolassist", funModel: mobel);
+
                 return Ok(new { state = 200, schoolAssist });
             }
             catch (Exception ex)
@@ -799,23 +784,11 @@ namespace TEAMModeBI.Controllers.BISchool
                 if (!jsonElement.TryGetProperty("periodName", out JsonElement _periodName)) return BadRequest();    //新增学段名称
                 if (!jsonElement.TryGetProperty("tmdId", out JsonElement _tmdId)) return BadRequest();   //醍摩豆账户
                 if (!jsonElement.TryGetProperty("tmdName", out JsonElement _tmdName)) return BadRequest(); //醍摩豆账号名称
-
-                var cosmosClient = _azureCosmos.GetCosmosClient();
-                //操作记录
-                OperateLog operateLog = new OperateLog();
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{_tmdId}";
-                operateLog.tmdName = $"{_tmdName}";
-                operateLog.visitApi = "/batchschool/upd-schoolPeriod ";
-                operateLog.operateTime = DateTime.Now;
+         
                 StringBuilder stringBuilder = new StringBuilder($"{_tmdId}【{_tmdName}】已操作新增学校的学段");
-
                 School school = new();
+
+                var cosmosClient = _azureCosmos.GetCosmosClient();
                 try
                 {
                     school = await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{_schoolCode}", new PartitionKey("Base"));
@@ -839,9 +812,9 @@ namespace TEAMModeBI.Controllers.BISchool
 
                     await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<School>(school, school.id, new PartitionKey("Base"));
 
-                    operateLog.operateDescribe = $"{stringBuilder}";
+                    //保存操作记录
+                    await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: stringBuilder?.ToString(), type: "schoolperiod-add", visitApi: "/batchschool/upd-schoolPeriod", funModel: mobel);
 
-                    await _azureStorage.Save<OperateLog>(operateLog);
                     return Ok(new { state = 200, school });
                 }
                 else return Ok(new { state = 400, school });
@@ -849,7 +822,7 @@ namespace TEAMModeBI.Controllers.BISchool
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"BI,{_option.Location}  /batchschool/upd-schoolPeriod   \n {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
+                await _dingDing.SendBotMsg($"BI,{_option.Location}  /batchschool/upd-schoolperiod   \n {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
                 return BadRequest();
             }
         }
@@ -871,21 +844,6 @@ namespace TEAMModeBI.Controllers.BISchool
                 if (!jsonElement.TryGetProperty("setId", out JsonElement _setId)) return BadRequest();          //修改学段的ID
                 if (!jsonElement.TryGetProperty("setName", out JsonElement _setName)) return BadRequest();           //修改学段的名称
 
-                //操作记录
-                OperateLog operateLog = new OperateLog();
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{_tmdId}";
-                operateLog.tmdName = $"{_tmdName}";
-                operateLog.visitApi = "/batchschool/set-schoolperiod";
-                operateLog.operateTime = DateTime.Now;
-                operateLog.operateDescribe = $"{_tmdId}【{_tmdName}】已操作修改学校学段信息,修改ID和名称:{_setId}{_setName}";
-                await _azureStorage.Save<OperateLog>(operateLog);
-
                 var cosmosClient = _azureCosmos.GetCosmosClient();
                 School school = new();
                 try
@@ -899,6 +857,10 @@ namespace TEAMModeBI.Controllers.BISchool
                     school.period.Find(x => x.id.Equals($"{_setId}")).name = $"{_setName}";
 
                     await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<School>(school, school.id, new PartitionKey("Base"));
+
+                    //保存操作记录
+                    await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdId}【{_tmdName}】已操作修改学校学段信息,修改ID和名称:{_setId}{_setName}", type: "schoolperiod-update", visitApi: "/batchschool/set-schoolperiod", funModel: mobel);
+
                     return Ok(new { state = 200, school });
                 }
                 else return Ok(new { state = 400, school });
@@ -926,22 +888,6 @@ namespace TEAMModeBI.Controllers.BISchool
                 if (!jsonElement.TryGetProperty("schooId", out JsonElement _schoolCode)) return BadRequest();   //学校编号
                 if (!jsonElement.TryGetProperty("delId", out JsonElement _delId)) return BadRequest();               //删除学段的ID
 
-                //操作记录
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog operateLog = new OperateLog
-                {
-                    PartitionKey = "OperateLog-BI",
-                    RowKey = blobOrTable,
-                    recordID = blobOrTable,
-                    platformSource = "BI",
-                    tmdId = $"{_tmdId}",
-                    tmdName = $"{_tmdName}",
-                    visitApi = "/batchschool/del-schoolperiod",
-                    operateTime = DateTime.Now,
-                    operateDescribe = $"{_tmdId}【{_tmdName}】已操作删除学校的学段,删除学段ID和名称:{_delId}"
-                };
-                await _azureStorage.Save<OperateLog>(operateLog);
-
                 var cosmosClient = _azureCosmos.GetCosmosClient();
                 School school = new();
                 try
@@ -955,6 +901,9 @@ namespace TEAMModeBI.Controllers.BISchool
                     school.period.Remove(school.period.Find(x => x.id.Equals($"{_delId}")));
                     await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<School>(school, school.id, new PartitionKey("Base"));
 
+                    //保存操作记录
+                    await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdId}【{_tmdName}】已操作删除学校的学段,删除学段ID和名称:{_delId}", type: "schoolperiod-del", visitApi: "/batchschool/del-schoolperiod", funModel: mobel);
+
                     return Ok(new { state = 200, school });
                 }
                 else return Ok(new { state = 400, school });
@@ -988,20 +937,8 @@ namespace TEAMModeBI.Controllers.BISchool
                 jsonElement.TryGetProperty("setName", out JsonElement _setName);              //修改学段的名称
                 jsonElement.TryGetProperty("delId", out JsonElement _delId);                  //删除学段的ID
 
-
-                //操作记录
-                OperateLog operateLog = new OperateLog();
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{_tmdId}";
-                operateLog.tmdName = $"{_tmdName}";
-                operateLog.visitApi = "/batchschool/set-schoolperiodinfo";
-                operateLog.operateTime = DateTime.Now;
                 StringBuilder stringBuilder = new StringBuilder($"{_tmdId}【{_tmdName}】已操作");
-
+                string tempType = null;
                 var cosmosClient = _azureCosmos.GetCosmosClient();
 
                 School school = new();
@@ -1023,6 +960,7 @@ namespace TEAMModeBI.Controllers.BISchool
                             {
                                 school.period.Add(new Period { id = Guid.NewGuid().ToString(), name = $"{_periodName}", campusId = $"{_campusId}" });
                                 stringBuilder.Append($"新增学校学段,在原有校区中添加学段:学段ID:{_campusId}学段名称:{_periodName}");
+
                             }
                             else
                             {
@@ -1032,25 +970,30 @@ namespace TEAMModeBI.Controllers.BISchool
 
                                 stringBuilder.Append($"新增学校学段,新建校区中在添加学段:学段ID:{_campusId}学段名称:{_periodName}");
                             }
+                            tempType = "schoolperiod-add";
                             break;
                         //修改学段
                         case "set":
                             school.period.Find(x => x.id.Equals($"{_setId}")).name = $"{_setName}";
                             stringBuilder.Append($"修改学校学段,修改ID和名称:{_setId}{_setName}");
+                            tempType = "schoolperiod-set";
                             break;
 
                         //删除学段
                         case "del":
                             school.period.Remove(school.period.Find(x => x.id.Equals($"{_delId}")));
                             stringBuilder.Append($"删除学校的学段,删除学段ID和名称:{_delId}");
+                            tempType = "schoolperiod-del";
                             break;
                         default:
                             return Ok(new { state = 1, message = "mode参数错误" });
                     }
-                    operateLog.operateDescribe = $"{stringBuilder}";
-                    await _azureStorage.Save<OperateLog>(operateLog);
+
+                    //保存操作记录
+                    await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: stringBuilder?.ToString(), type: tempType?.ToString(), visitApi: "/batchschool/set-schoolperiodinfo", funModel: mobel);
 
                     await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<School>(school, school.id, new PartitionKey("Base"));
+
                     return Ok(new { state = 200, school });
                 }
                 else return Ok(new { state = 400, school });

+ 5 - 18
TEAMModeBI/Controllers/BISchool/SchoolController.cs

@@ -10,6 +10,7 @@ using System.Threading.Tasks;
 using TEAMModelOS.Models;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Helper.Common.TableHelper;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos.BI;
 
@@ -23,6 +24,7 @@ namespace TEAMModeBI.Controllers.BISchool
         private readonly DingDing _dingDing;
         private readonly Option _option;
         private readonly AzureStorageFactory _azureStorage;
+        public readonly string mobel = "学校";
 
         public SchoolController(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage, IOptionsSnapshot<Option> option) 
         {
@@ -98,23 +100,7 @@ namespace TEAMModeBI.Controllers.BISchool
                 List<string> schoolCodes = _schoolCode.ToObject<List<string>>();
 
                 var cosmosCliet = _azureCosmos.GetCosmosClient();
-                //操作记录
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog operateLog = new OperateLog
-                {
-                    PartitionKey = "OperateLog-BI",
-                    RowKey = blobOrTable,
-                    recordID = blobOrTable,
-                    platformSource = "BI",
-                    tmdId = $"{_tmdId}",
-                    tmdName = $"{_tmdName}",
-                    visitApi = "/schoolcheck/set-schooljoinarea",
-                    operateType = "修改",
-                    funModule = "学校",
-                    operateTime = DateTime.Now,
-                    operateDescribe = $"{_tmdName}【{_tmdId}】已操作学校加入区域功能,加入的区域:{standard},学校ID:{string.Join("|", schoolCodes.ToArray())}"
-                };
-
+                
                 if (schoolCodes.Count > 0) 
                 {
                     foreach (var tempCode in schoolCodes) 
@@ -129,7 +115,8 @@ namespace TEAMModeBI.Controllers.BISchool
                     }
                 }
 
-                await _azureStorage.Save<OperateLog>(operateLog);   //保存操作记录
+                //保存操作记录
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdName}【{_tmdId}】已操作学校加入区域功能,加入的区域:{standard},学校ID:{string.Join("|", schoolCodes.ToArray())}", type: "school-join", visitApi: "/schoolcheck/set-schooljoinarea", funModel: mobel);
 
                 return Ok(new { state = 200 });
             }

+ 53 - 17
TEAMModeBI/Controllers/BITest/TestController.cs

@@ -2,6 +2,7 @@
 using DingTalk.Api;
 using DingTalk.Api.Request;
 using DingTalk.Api.Response;
+using HTEXLib.COMM.Helpers;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
@@ -18,6 +19,7 @@ using TEAMModelOS.Models;
 using TEAMModelOS.SDK;//引用创建学校Code
 using TEAMModelOS.SDK.Context.Attributes.Azure;
 using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Helper.Common.TableHelper;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos.BI;
 using TEAMModelOS.SDK.Models.Service;
@@ -37,6 +39,7 @@ namespace TEAMModeBI.Controllers.BITest
         private readonly IWebHostEnvironment _environment; //读取文件
         //读取配置文件
         private readonly IConfiguration _configuration;
+        public readonly string mobel = "测试接口";
 
         public TestController(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage, IOptionsSnapshot<Option> option, IWebHostEnvironment hostingEnvironment, IConfiguration configuration)
         {
@@ -207,15 +210,6 @@ namespace TEAMModeBI.Controllers.BITest
             try
             {
                 List<BISchool> schools = new List<BISchool>();
-                //操作记录
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog operateLog = new OperateLog();
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{foundSchools.tmdId}";
-                operateLog.tmdName = $"{foundSchools.tmdName}";
                 StringBuilder stringBuilder = new StringBuilder($"{foundSchools.tmdName}【{foundSchools.tmdId}】操作了批量创校功能;");
                 List<School> tempSchools = new List<School>();
 
@@ -337,7 +331,7 @@ namespace TEAMModeBI.Controllers.BITest
                                     ttl = -1
                                 };
                                 stringBuilder.Append($"教师信息:{schoolTeacher.name}【{schoolTeacher.id}】,教师权限:{schoolTeacher.roles.ToString()}");
-                                await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync<SchoolTeacher>(schoolTeacher, new PartitionKey(schoolTeacher.code));
+                                await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync<SchoolTeacher>(schoolTeacher, new PartitionKey(schoolTeacher.code));
                             }
                             else
                             {
@@ -371,16 +365,15 @@ namespace TEAMModeBI.Controllers.BITest
                                     ttl = -1
                                 };
                                 stringBuilder.Append($"教师权限:{schoolTeacher.roles}");
-                                await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").UpsertItemAsync<SchoolTeacher>(schoolTeacher, new PartitionKey(schoolTeacher.code));
+                                await cosmosClient.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync<SchoolTeacher>(schoolTeacher, new PartitionKey(schoolTeacher.code));
                             }
                         }
                     }
                 }
                 else return Ok(new { state = 1, message = "创校信息为空" });
-                operateLog.operateDescribe = $"{stringBuilder}";
-                operateLog.visitApi = "/batchschool/batch-school";
-                operateLog.operateTime = DateTime.Now;
-                await _azureStorage.Save<OperateLog>(operateLog);
+
+                //保存操作记录
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{foundSchools.tmdId}", tmdName: $"{foundSchools.tmdName}", msg: stringBuilder?.ToString(), type: "api-test", visitApi: "/batchschool/batch-school", funModel: mobel);
 
                 if (schools.Count > 0)
                     return Ok(new { state = 201, message = "已有部分学校批量创建成功;学校编号已经重复!请检查学校编号!", schools = schools });
@@ -584,11 +577,54 @@ namespace TEAMModeBI.Controllers.BITest
             {
                 pageTest1 pageTest = new pageTest1();
                 pageTest.keyt = $"分页{i}";
-                pageTest.listv = st.Skip(i).Take(st.Count - i).ToList();
+                pageTest.listv = st.Skip(i).Take(1).ToList();
                 pageTests1.Add(pageTest);
             }
 
-            return Ok(new { pageTests, pageTests1 });
+            return Ok(new {  pageTests1 });
+        }
+
+        [HttpPost("del-standard")]
+        public async Task<IActionResult> DelStandard(JsonElement jsonElement) 
+        {
+            if (!jsonElement.TryGetProperty("oldStandard", out JsonElement _oldStandard)) return BadRequest();
+            var cosmosClient = _azureCosmos.GetCosmosClient();
+
+            List<string> abilityIds = new List<string>();  //册别的ID集合
+
+            //查询册别信息
+            await foreach (var tempAbility in cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Ability>(queryText: $"select value(c) from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Ability-{_oldStandard}") }))
+            {
+                abilityIds.Add(tempAbility.id);  //查询出来册别ID添加册别ID集合
+            }
+            //删除册别
+            if (abilityIds.IsNotEmpty())
+            {
+                //var sresponse = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").DeleteItemsStreamAsync(abilityIds, $"Ability-{_oldStandard}");
+            }
+
+            List<string> abilityTaskIds = new List<string>();  //章节ID集合
+            foreach (var abilityId in abilityIds)
+            {
+                await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<AbilityTask>(queryText: $"select value(c) from c where c.abilityId='{abilityId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"AbilityTask-{_oldStandard}") }))
+                {
+                    abilityTaskIds.Add(item.id);   //查询出来的章节信息ID添加到战绩集合
+                }
+            }
+            //删除章节
+            if (abilityTaskIds.IsNotEmpty())
+            {
+                //var sresponse = await cosmosClient.GetContainer(Constant.TEAMModelOS, "Normal").DeleteItemsStreamAsync(abilityTaskIds, $"AbilityTask-{_oldStandard}");
+            }
+
+            return Ok(new { state = 200 });
+        }
+
+        [HttpPost("save-tablelog")]
+        public async Task<IActionResult> SaveTableLogTest() 
+        {
+            await OperateLogHelper.SaveTableLog(_azureStorage, "BI", "1636016499", "彭礼", "测试保存方法", "table-save", "save-tablelog");
+            return Ok(123);
         }
 
         public record pageTest

+ 4 - 18
TEAMModeBI/Controllers/DingDingStruc/DDBackEndController.cs

@@ -21,6 +21,7 @@ using System.Net;
 using HTEXLib.COMM.Helpers;
 using TEAMModelOS.SDK.Models.Cosmos.BI;
 using System.Net.Http.Json;
+using TEAMModelOS.SDK.Helper.Common.TableHelper;
 
 namespace TEAMModeBI.Controllers.DingDingStruc
 {
@@ -104,24 +105,6 @@ namespace TEAMModeBI.Controllers.DingDingStruc
                     userid = v2GetResponse.Result.Userid,
                 };
 
-                //操作记录实体
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog operateLog = new OperateLog
-                {
-                    PartitionKey = "OperateLog-BI",
-                    RowKey = blobOrTable,
-                    recordID = blobOrTable,
-                    platformSource = "BI",
-                    tmdId = $"{_tmdId}",
-                    tmdName = $"{_tmdName}",
-                    operateDescribe = $"{_tmdName}【{_tmdId}】已操作创区功能",
-                    visitApi = "ddbackend/get-backendbind",
-                    operateTime = DateTime.Now
-                };
-                //保存操作记录
-                await _azureStorage.Save<OperateLog>(operateLog);
-
-
                 //检查是否有绑定信息
                 var client = _azureCosmos.GetCosmosClient();
                 Teacher teacher = null;
@@ -174,6 +157,9 @@ namespace TEAMModeBI.Controllers.DingDingStruc
                     else return Ok(new { state = 2, message = "醍摩豆账户有误,请检查醍摩豆账户!" });
                 }
 
+                //保存操作记录
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdName}【{_tmdId}】醍摩豆账号和{v2GetResponse.Result.Name}【{v2GetResponse.Result.Userid}】钉钉账户绑定成功", type: "tabledd-del", visitApi: "/ddbackend/get-backendbind", funModel: "绑定");
+
                 return Ok(new { state = 200, message = "绑定成功!" });
             }
             catch (Exception ex)

+ 15 - 62
TEAMModeBI/Controllers/DingDingStruc/TableDingDingInfoController.cs

@@ -20,6 +20,7 @@ using TEAMModelOS.SDK.Extension;
 using OpenXmlPowerTools;
 using System.Text;
 using Azure.Cosmos;
+using TEAMModelOS.SDK.Helper.Common.TableHelper;
 
 namespace TEAMModeBI.Controllers.DingDingStruc
 {
@@ -37,6 +38,7 @@ namespace TEAMModeBI.Controllers.DingDingStruc
         private readonly DingDing _dingDing;
         private readonly Option _option;
         private readonly IHttpClientFactory _http;
+        public readonly string mobel = "组织员工";
 
         public TableDingDingInfoController(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage, IOptionsSnapshot<Option> option, IConfiguration configuration, IHttpClientFactory http)
         {
@@ -61,23 +63,6 @@ namespace TEAMModeBI.Controllers.DingDingStruc
                 if (!jsonElement.TryGetProperty("tmdId", out JsonElement _tmdId)) return BadRequest();   //醍摩豆账户
                 if (!jsonElement.TryGetProperty("tmdName", out JsonElement _tmdName)) return BadRequest(); //醍摩豆账号名称
 
-                //操作记录;
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog operateLog = new OperateLog()
-                {
-                    PartitionKey = "OperateLog-BI",
-                    RowKey = blobOrTable,
-                    recordID = blobOrTable,
-                    platformSource = "BI",
-                    tmdId = $"{_tmdId}",
-                    tmdName = $"{_tmdName}",
-                    visitApi = "/tabledd/get-dingdingusers",
-                    operateTime = DateTime.Now,
-                    operateType = "修改",
-                    funModule = "钉钉信息",
-                    operateDescribe = $"{_tmdName}【{_tmdId}】账户操作从钉钉组织结构更新至Azure Table表【DDUserInfo】中。"
-                };
-
                 string appKey = _configuration["DingDingAuth:appKey"];
                 string appSecret = _configuration["DingDingAuth:appSecret"];
 
@@ -174,7 +159,8 @@ namespace TEAMModeBI.Controllers.DingDingStruc
                     }
                 }
 
-                await _azureStorage.Save<OperateLog>(operateLog); //保存操作记录
+                //保存操作记录
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdName}【{_tmdId}】账户操作从钉钉组织结构更新至Azure Table表【DDUserInfo】中。", type: "tabledd-update", visitApi: "/tabledd/get-dingdingusers", funModel: mobel);
 
                 var tempddUserInfos = ddUserInfos.GroupBy(c => c.RowKey).Select(c => c.First()).ToList();//去重
                 //List<DingDingUserInfo> TempdingDingUserInfos = await _azureStorage.SaveOrUpdateAll(dingDingUserInfos);  //只是保存至Table
@@ -259,19 +245,6 @@ namespace TEAMModeBI.Controllers.DingDingStruc
 
                 string divide = _configuration["CustomParam:SiteScope"];
 
-                //操作记录
-                OperateLog operateLog = new OperateLog();
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{_tmdId}";
-                operateLog.tmdName = $"{_tmdName}";
-                operateLog.visitApi = "/tabledd/set-ddinductionuser";
-                operateLog.operateTime = DateTime.Now;
-                operateLog.operateDescribe = $"{_tmdName}【{_tmdId}】已操作添加待入职员工至table数据表中";
-
                 //获取access_token
                 IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
                 OapiGettokenRequest request = new OapiGettokenRequest() { Appkey = appKey, Appsecret = appSecret };
@@ -301,7 +274,10 @@ namespace TEAMModeBI.Controllers.DingDingStruc
                     }
 
                     List<DingDingUserInfo> tempddUserInfos = await _azureStorage.SaveAll(ddUserInfos);
-                    await _azureStorage.Save<OperateLog>(operateLog); //保存操作记录
+
+                    //保存操作记录
+                    await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdName}【{_tmdId}】已操作添加待入职员工至table数据表中", type: "tabledd-add", visitApi: "/tabledd/set-ddinductionuser", funModel: mobel);
+
                     if (ddUserInfos.Count == tempddUserInfos.Count)
                     {
                         return Ok(new { state = 200, UserInfo = tempddUserInfos });
@@ -341,19 +317,6 @@ namespace TEAMModeBI.Controllers.DingDingStruc
                 string appSecret = _configuration["DingDingAuth:appSecret"];
                 string divide = _configuration["CustomParam:SiteScope"];
 
-                //操作记录
-                OperateLog operateLog = new OperateLog();
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{_tmdId}";
-                operateLog.tmdName = $"{_tmdName}";
-                operateLog.visitApi = "/tabledd/del-ddquituser";
-                operateLog.operateTime = DateTime.Now;
-                operateLog.operateDescribe = $"{_tmdName}【{_tmdId}】已操作从table数据表中删除离职员工";
-
                 //获取access_token
                 IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
                 OapiGettokenRequest request = new OapiGettokenRequest() { Appkey = appKey, Appsecret = appSecret };
@@ -378,7 +341,9 @@ namespace TEAMModeBI.Controllers.DingDingStruc
                         await _azureStorage.DeleteSingle<DingDingUserInfo>(divide, $"{itemId}");
                     }
 
-                    await _azureStorage.Save<OperateLog>(operateLog); //保存操作记录
+                    //保存操作记录
+                    await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: $"{_tmdName}【{_tmdId}】已操作从table数据表中删除离职员工", type: "tabledd-del", visitApi: "/tabledd/del-ddquituser", funModel: mobel);
+
                     return Ok(new { state = 200 });
                 }
                 else
@@ -411,19 +376,6 @@ namespace TEAMModeBI.Controllers.DingDingStruc
                 if (!jsonElement.TryGetProperty("rowKey", out JsonElement userId)) return BadRequest();
                 if (!jsonElement.TryGetProperty("permissions", out JsonElement _permissions)) return BadRequest();
 
-                //操作记录
-                OperateLog operateLog = new OperateLog();
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{_tmdId}";
-                operateLog.tmdName = $"{_tmdName}";
-                operateLog.operateType = "修改";
-                operateLog.funModule = "权限";
-                operateLog.visitApi = "/tabledd/set-permissions";
-                operateLog.operateTime = DateTime.Now;
                 StringBuilder stringBuilder = new StringBuilder($"{_tmdName}【{_tmdId}】醍摩豆账号");
                 List<DingDingUserInfo> ddUserInfo = new List<DingDingUserInfo>();
                 var tempUser = await _azureStorage.FindListByDict<DingDingUserInfo>(new Dictionary<string, object> { { "PartitionKey", $"{partitionKey}" }, { "RowKey", $"{userId}" } });
@@ -433,7 +385,7 @@ namespace TEAMModeBI.Controllers.DingDingStruc
 
                 foreach (var item in tempUser)
                 {
-                    stringBuilder.Append($"操作醍摩豆账户{item.tmdName}【{item.tmdId}】修改权限:{string.Join(" ", listper.ToArray())}");
+                    stringBuilder.Append($"操作醍摩豆账户{item.tmdName}【{item.tmdId}】修改权限:{string.Join("|", listper.ToArray())}");
                     if (string.IsNullOrEmpty($"{item.roles}"))
                     {
                         item.roles = "assist";
@@ -453,8 +405,9 @@ namespace TEAMModeBI.Controllers.DingDingStruc
 
                 ddUserInfo = await _azureStorage.UpdateAll<DingDingUserInfo>(ddUserInfo);
 
-                operateLog.operateDescribe = stringBuilder.ToString();
-                await _azureStorage.Save<OperateLog>(operateLog);  //保存操作记录
+                //保存操作记录
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: stringBuilder?.ToString(), type: "tabledd-del", visitApi: "/tabledd/set-permissions", funModel: "BI权限");
+
                 return Ok(new { state = 200, ddUserInfo, roles, permissions });
             }
             catch (Exception ex)

+ 13 - 443
TEAMModeBI/Controllers/LoginController.cs

@@ -29,6 +29,7 @@ using Newtonsoft.Json.Linq;
 using TEAMModelOS.SDK.Models.Cosmos.BI;
 using Azure.Storage.Sas;
 using System.Net.Http.Json;
+using TEAMModelOS.SDK.Helper.Common.TableHelper;
 //using static DingTalk.Api.Response.OapiV2UserGetResponse;
 
 namespace TEAMModeBI.Controllers
@@ -255,410 +256,6 @@ namespace TEAMModeBI.Controllers
             }
         }
 
-        /// <summary>
-        /// 钉钉绑定醍摩豆信息
-        /// </summary>
-        /// <param name="ddbindparam"></param>
-        /// <returns></returns>
-        [ProducesDefaultResponseType]
-        [HttpPost("bind")]
-        [AllowAnonymous]
-        public async Task<IActionResult> Bind(JsonElement jsonElement)
-        {
-            try
-            {
-                jsonElement.TryGetProperty("mobile", out JsonElement mobile);
-                jsonElement.TryGetProperty("idToken", out JsonElement idToken);
-                if (!jsonElement.TryGetProperty("param", out JsonElement param)) return BadRequest();
-
-                HttpClient httpClient = _http.CreateClient();
-                Teacher teacher = new Teacher();
-                DingDingbinds ddbinds = param.ToObject<DingDingbinds>();  //将json数据转换为实体类
-                TmdidImplicit implicit_token = new TmdidImplicit();
-
-                Dictionary<string, object> dic = new Dictionary<string, object> { { "PartitionKey", "authority-bi" } };//设置只访问BI的权限
-                List<Authority> authorityBIList = await _azureStorage.FindListByDict<Authority>(dic);  //获取权限列表
-                List<string> roles = new List<string>();//角色列表
-                List<string> permissions = new List<string>();//权限列表
-                List<string> depts = new List<string>();    //部门id
-                School school_base = new School();
-                string school_code = null;
-                var auth_token = "";
-
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                OperateLog operateLog = new OperateLog();//操作记录
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{teacher.id}";
-                operateLog.tmdName = $"{teacher.name}";
-                operateLog.visitApi = "common/login/bind";
-                operateLog.operateTime = DateTime.Now;
-
-                StringBuilder strBuilder = new StringBuilder();
-
-                if (!string.IsNullOrEmpty($"{mobile}")) 
-                {
-                    List<JsonElement> mbs = new List<JsonElement>() { mobile };
-                    string url = _configuration.GetValue<string>("HaBookAuth:CoreId:userinfo");
-
-                    HttpResponseMessage responseMessage = await httpClient.PostAsJsonAsync(url, mbs);
-                    if (responseMessage.StatusCode == HttpStatusCode.OK)
-                    {
-                        string responseBody = await responseMessage.Content.ReadAsStringAsync();
-                        List<JsonElement> json_id = responseBody.ToObject<List<JsonElement>>();
-                        string temp_id = null;
-                        if (json_id.IsNotEmpty()) 
-                        {
-                            temp_id = json_id[0].GetProperty("id").ToString();
-                        }
-
-                        var client = _azureCosmos.GetCosmosClient();
-                        teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>(temp_id, new PartitionKey("Base"));
-
-                        string sql = $"SELECT distinct value(c) FROM c join A1 in c.ddbinds where A1.userid='{ddbinds.userid}' and A1.unionid='{ddbinds.unionid}'";
-                        await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<Teacher>(queryText: sql,
-                            requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
-                        {
-                            teacher = item;
-                            break;
-                        }
-                        if (teacher != null)
-                        {
-                            if (teacher.id.Equals(temp_id))
-                            {
-                                var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
-                                var location = _option.Location;
-                                implicit_token  = await _aoreAPIHttpService.Implicit(
-                                    new Dictionary<string, string>()
-                                    {
-                                        { "grant_type", "implicit" },
-                                        { "client_id",clientID },
-                                        { "account",teacher.id },
-                                        { "nonce",Guid.NewGuid().ToString()}
-                                    }, location, _configuration);
-
-                                if (implicit_token!=null)
-                                {
-                                    var ddbind = teacher.ddbinds.Find(x => x.userid.Equals($"{ddbinds.userid}") && x.unionid.Equals($"{ddbinds.unionid}"));
-                                    if (ddbind == null)
-                                    {
-                                        teacher.ddbinds = new List<Teacher.DingDingBind> { new Teacher.DingDingBind { type = $"{type}", deptIdList = ddbinds.deptIdList, title = ddbinds.title, name = ddbinds.name, unionid = ddbinds.unionid, userid = ddbinds.userid } };
-                                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, teacher.id, new PartitionKey(teacher.code));
-
-                                        if (teacher.defaultSchool != null)
-                                        {
-                                            var schoolRoles = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(teacher.id, new PartitionKey($"Teacher-{teacher.defaultSchool}"));
-                                            if (schoolRoles.Status == 200)
-                                            {
-                                                using var json = await JsonDocument.ParseAsync(schoolRoles.ContentStream);
-                                                if (json.RootElement.TryGetProperty("roles", out JsonElement _roles) && _roles.ValueKind != JsonValueKind.Null)
-                                                {
-                                                    foreach (var obj in _roles.EnumerateArray())
-                                                    {
-                                                        //初始定义顾问的assistant 更改为assist
-                                                        if (obj.GetString().Equals($"assist"))
-                                                        {
-                                                            roles.Add(obj.GetString());
-                                                        }
-                                                    }
-                                                }
-                                                if (json.RootElement.TryGetProperty("permissions", out JsonElement _permissions) && _permissions.ValueKind != JsonValueKind.Null)
-                                                {
-                                                    foreach (var obj in _permissions.EnumerateArray())
-                                                    {
-                                                        //限制只显示BI权限
-                                                        foreach (var aut in authorityBIList)
-                                                        {
-                                                            if (aut.RowKey.Equals(obj.GetString()))
-                                                            {
-                                                                permissions.Add(obj.GetString());
-                                                            }
-                                                        }
-                                                    }
-                                                }
-                                            }
-
-                                            school_base = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{teacher.defaultSchool}", new PartitionKey("Base"));
-                                            //foreach (var period in school_base.period)
-                                            //{
-                                            //    try
-                                            //    {
-                                            //        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<ItemCond>($"{period.id}", new PartitionKey($"ItemCond-{teacher.defaultSchool}"));
-                                            //    }
-                                            //    catch (CosmosException)
-                                            //    {
-                                            //        ItemCond itemCond = new ItemCond
-                                            //        {
-                                            //            id = period.id,
-                                            //            pk = "ItemCond",
-                                            //            code = $"ItemCond-{teacher.defaultSchool}",
-                                            //            ttl = -1,
-                                            //        };
-                                            //        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync<ItemCond>(itemCond, new PartitionKey($"ItemCond-{teacher.defaultSchool}"));
-                                            //    }
-                                            //}
-                                            school_code = teacher.defaultSchool;
-                                        }
-
-                                        foreach (var tempdept in ddbinds.deptIdList)
-                                        {
-                                            depts.Add(tempdept.ToString());
-                                        }
-                                        strBuilder.Append($"醍摩豆账户{teacher.id}【{teacher.name}】和钉钉账户{ddbinds.userid}【{ddbinds.name}】进行绑定,绑定成功");
-                                    }
-                                }
-                                else 
-                                {
-                                    if (teacher.ddbinds.IsNotEmpty()) 
-                                    {
-                                        teacher.ddbinds.RemoveAll(x => x.userid.Equals(ddbinds.userid) && x.unionid.Equals(ddbinds.unionid));
-                                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, teacher.id, new PartitionKey(teacher.code));
-                                    }
-
-                                    strBuilder.Append($"醍摩豆账户{teacher.id}【{teacher.name}】和钉钉账户{ddbinds.userid}【{ddbinds.name}】进行绑定,绑定失败");
-                                    operateLog.operateDescribe = strBuilder.ToString();
-                                    await _azureStorage.Save<OperateLog>(operateLog);
-                                    return Ok(new { state = 1, message = "绑定失败" });                                
-                                }
-                            }
-                            else
-                            {
-                                operateLog.operateDescribe = $"醍摩豆账户{teacher.id}【{teacher.name}】和钉钉账户{ddbinds.userid}【{ddbinds.name}】进行绑定,账号已被别的醍摩豆id绑定";
-                                await _azureStorage.Save<OperateLog>(operateLog);
-
-                                return Ok(new
-                                {
-                                    location = _option.Location,
-                                    //账号已被别的醍摩豆id绑定
-                                    state = 2,
-                                    tmdid = teacher.id,
-                                    name = teacher.name,
-                                    ddid = ddbinds.userid,
-                                    ddname = ddbinds.name
-                                });
-                            }
-                        }
-                        else 
-                        {
-                            teacher = new Teacher
-                            {
-                                id = temp_id,
-                                pk = "Base",
-                                code = "Base",
-                                name = temp_id,
-                                //创建账号并第一次登录IES5则默认赠送1G
-                                size = 1,
-                                defaultSchool = null,
-                                schools = new List<Teacher.TeacherSchool>(),
-                                ddbinds = new List<Teacher.DingDingBind> { new Teacher.DingDingBind { type = $"{type}", deptIdList = ddbinds.deptIdList, title = ddbinds.title, name = ddbinds.name, unionid = ddbinds.unionid, userid = ddbinds.userid } },
-                            };
-                            var container = _azureStorage.GetBlobContainerClient(temp_id);
-                            await container.CreateIfNotExistsAsync(PublicAccessType.None); //尝试创建Teacher私有容器,如存在则不做任何事,保障容器一定存在
-                            teacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<Teacher>(teacher, new PartitionKey("Base"));
-
-                            foreach (var tempdept in ddbinds.deptIdList)
-                            {
-                                depts.Add(tempdept.ToString());
-                            }
-
-                            auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, teacher.id, teacher.name?.ToString(), teacher.picture?.ToString(), _option.JwtSecretKey, scope: Constant.ScopeTeacher, schoolID: school_code?.ToString(), standard: school_base.standard, roles: roles.ToArray(), permissions: permissions.ToArray(), ddDepts: depts.ToArray(), ddsub: ddbinds.userid);
-
-                            strBuilder.Append($"醍摩豆账户{teacher.id}【{teacher.name}】和钉钉账户{ddbinds.userid}【{ddbinds.name}】进行绑定,新建的账户绑定成功");
-                     
-                        }
-                    }
-                    else
-                    {
-                        return Ok(new { state = 3, message = "通过手机号查询用户信息异常" });
-                    }
-                }
-
-                if (!string.IsNullOrEmpty($"{idToken}"))
-                {
-                    var jwt = new JwtSecurityToken($"{idToken}");
-                    //if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
-                    var id = jwt.Payload.Sub;
-                    jwt.Payload.TryGetValue("name", out object name);
-                    jwt.Payload.TryGetValue("picture", out object picture);
-                    //检查是否有绑定信息
-                    var client = _azureCosmos.GetCosmosClient();
-                    teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>(id, new PartitionKey("Base"));
-                    string sql = $"select distinct value(c) from c join A1 in c.ddbinds where A1.userid='{ddbinds.userid}' AND A1.unionid ='{ddbinds.unionid}'";
-                    await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<Teacher>(queryText: sql,
-                        requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
-                    {
-                        teacher = item;
-                        break;
-                    }
-
-                    if (teacher != null)
-                    {
-                        if (teacher.id.Equals(id))
-                        {
-                            var ddbind = teacher.ddbinds.Find(x => x.userid.Equals($"{ddbinds.userid}") && x.unionid.Equals($"{ddbinds.unionid}"));
-                            if (ddbind == null)
-                            {
-                                teacher.ddbinds = new List<Teacher.DingDingBind> { new Teacher.DingDingBind { type = $"{type}", deptIdList = ddbinds.deptIdList, title = ddbinds.title, name = ddbinds.name, unionid = ddbinds.unionid, userid = ddbinds.userid } };
-                                await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<Teacher>(teacher, teacher.id, new PartitionKey(teacher.code));
-                                
-                                //添加
-                                if (teacher.defaultSchool != null)
-                                {
-                                    var schoolRoles = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(teacher.id, new PartitionKey($"Teacher-{teacher.defaultSchool}"));
-                                    if (schoolRoles.Status == 200)
-                                    {
-                                        using var json = await JsonDocument.ParseAsync(schoolRoles.ContentStream);
-                                        if (json.RootElement.TryGetProperty("roles", out JsonElement _roles) && _roles.ValueKind != JsonValueKind.Null)
-                                        {
-                                            foreach (var obj in _roles.EnumerateArray())
-                                            {
-                                                //初始定义顾问的assistant 更改为assist
-                                                if (obj.GetString().Equals($"assist"))
-                                                {
-                                                    roles.Add(obj.GetString());
-                                                }
-                                            }
-                                        }
-                                        if (json.RootElement.TryGetProperty("permissions", out JsonElement _permissions) && _permissions.ValueKind != JsonValueKind.Null)
-                                        {
-                                            foreach (var obj in _permissions.EnumerateArray())
-                                            {
-                                                //限制只显示BI权限
-                                                foreach (var aut in authorityBIList)
-                                                {
-                                                    if (aut.RowKey.Equals(obj.GetString()))
-                                                    {
-                                                        permissions.Add(obj.GetString());
-                                                    }
-                                                }
-                                            }
-                                        }
-                                    }
-
-                                    school_base = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{teacher.defaultSchool}", new PartitionKey("Base"));
-                                    //foreach (var period in school_base.period)
-                                    //{
-                                    //    try
-                                    //    {
-                                    //        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<ItemCond>($"{period.id}", new PartitionKey($"ItemCond-{teacher.defaultSchool}"));
-                                    //    }
-                                    //    catch (CosmosException)
-                                    //    {
-                                    //        ItemCond itemCond = new ItemCond
-                                    //        {
-                                    //            id = period.id,
-                                    //            pk = "ItemCond",
-                                    //            code = $"ItemCond-{teacher.defaultSchool}",
-                                    //            ttl = -1,
-                                    //        };
-                                    //        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync<ItemCond>(itemCond, new PartitionKey($"ItemCond-{teacher.defaultSchool}"));
-                                    //    }
-                                    //}
-                                    school_code = teacher.defaultSchool;
-                                }
-
-                                foreach (var tempdept in ddbinds.deptIdList)
-                                {
-                                    depts.Add(tempdept.ToString());
-                                }
-                            }
-
-                            auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, teacher.id, teacher.name?.ToString(), teacher.picture?.ToString(), _option.JwtSecretKey, scope: Constant.ScopeTeacher, schoolID: school_code?.ToString(), standard: school_base.standard, roles: roles.ToArray(), permissions: permissions.ToArray(), ddDepts: depts.ToArray(), ddsub: ddbinds.userid);
-
-                            operateLog.operateDescribe = $"新建的账户的醍摩豆账户{teacher.id}【{teacher.name}】和钉钉账户{ddbinds.userid}【{ddbinds.name}】进行绑定,绑定成功";
-                            await _azureStorage.Save<OperateLog>(operateLog);
-
-                            return Ok(new
-                            {
-                                state = 200,
-                                auth_token = auth_token,
-                                idToken = idToken,
-                                teacher = teacher,
-                                location = _option.Location,
-                            });
-                        }
-                        else
-                        {
-                            operateLog.operateDescribe = $"醍摩豆账户{teacher.id}【{teacher.name}】和钉钉账户{ddbinds.userid}【{ddbinds.name}】进行绑定,账号已被别的醍摩豆id绑定";
-                            await _azureStorage.Save<OperateLog>(operateLog);
-
-                            return Ok(new
-                            {
-                                location = _option.Location,
-                                //账号已被别的醍摩豆id绑定
-                                state = 2,
-                                tmdid = teacher.id,
-                                name = teacher.name,
-                                userid = ddbinds.userid,
-                                ddname = ddbinds.name
-                            });
-                        }
-                    }
-                    else
-                    {
-                        teacher = new Teacher
-                        {
-                            id = id,
-                            pk = "Base",
-                            code = "Base",
-                            name = name?.ToString(),
-                            picture = picture?.ToString(),
-                            //创建账号并第一次登录IES5则默认赠送1G
-                            size = 1,
-                            defaultSchool = null,
-                            schools = new List<Teacher.TeacherSchool>(),
-                            ddbinds = new List<Teacher.DingDingBind> { new Teacher.DingDingBind { type = $"{type}", deptIdList = ddbinds.deptIdList, title = ddbinds.title, name = ddbinds.name, unionid = ddbinds.unionid, userid = ddbinds.userid } }
-                        };
-
-                        var container = _azureStorage.GetBlobContainerClient(id);
-                        await container.CreateIfNotExistsAsync(PublicAccessType.None); //尝试创建Teacher私有容器,如存在则不做任何事,保障容器一定存在
-                        teacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<Teacher>(teacher, new PartitionKey("Base"));
-
-                        foreach (var tempdept in ddbinds.deptIdList)
-                        {
-                            depts.Add(tempdept.ToString());
-                        }
-
-                        auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, teacher.id, teacher.name?.ToString(), teacher.picture?.ToString(), _option.JwtSecretKey, scope: Constant.ScopeTeacher, schoolID: school_code?.ToString(), standard: school_base.standard, roles: roles.ToArray(), permissions: permissions.ToArray(), ddDepts: depts.ToArray(), ddsub: ddbinds.userid);
-
-                        strBuilder.Append($"醍摩豆账户{teacher.id}【{teacher.name}】和钉钉账户{ddbinds.userid}【{ddbinds.name}】进行绑定,新建的账户绑定成功");                        
-                        await _azureStorage.Save<OperateLog>(operateLog);
-                        return Ok(new
-                        {
-                            state = 200,
-                            auth_token = auth_token,
-                            idToken = id,
-                            //teacher = teacher,
-                            location = _option.Location,
-                        });
-                    }
-                }
-
-                auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, teacher.id, teacher.name?.ToString(), teacher.picture?.ToString(), _option.JwtSecretKey, scope: Constant.ScopeTeacher, schoolID: school_code.ToString(), standard: school_base.standard, roles: roles.ToArray(), permissions: permissions.ToArray(), ddDepts: depts.ToArray(), ddsub: ddbinds.userid);
-                string temp_idToken = string.IsNullOrEmpty($"{idToken}") ? implicit_token.id_token : idToken.ToString();
-                operateLog.operateDescribe = strBuilder.ToString();
-                return Ok(new
-                {
-                    state = 200,
-                    auth_token = auth_token,
-                    idToken = temp_idToken,
-                    teacher = teacher,
-                    location = _option.Location,
-                });
-            }
-            catch (Exception ex)
-            {
-                await _dingDing.SendBotMsg($"BI,{_option.Location} common/login/bind   \n {ex.Message}{ex.StackTrace} ", GroupNames.成都开发測試群組);
-                return Ok(new
-                {
-                    state = 1,
-                    location = _option.Location                    
-                });
-            }
-        }
-
         /// <summary>
         /// 依据id_Ttoken获取教师信息
         /// </summary>
@@ -927,16 +524,6 @@ namespace TEAMModeBI.Controllers
                 if (!jsonElement.TryGetProperty("partitionKey", out JsonElement partitionKey)) return BadRequest();
                 if (!jsonElement.TryGetProperty("rowKey", out JsonElement userId)) return BadRequest();
 
-                //操作记录
-                OperateLog operateLog = new OperateLog();
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.visitApi = "/common/login/set-ddinductionuser";
-                operateLog.operateTime = DateTime.Now;
-
                 HttpClient httpClient = _http.CreateClient();
                 string url = _configuration.GetValue<string>("HaBookAuth:CoreId:userinfo");
                 HttpResponseMessage responseMessage = await httpClient.PostAsJsonAsync(url, moile);
@@ -961,25 +548,20 @@ namespace TEAMModeBI.Controllers
                                 itemUser.picture = item.GetProperty("picture").ToString();
                                 itemUser.mail = item.GetProperty("mail").ToString();
 
-                                operateLog.operateType = "修改";
-                                operateLog.funModule = "钉钉绑定";
-                                operateLog.tmdId = item.GetProperty("id").ToString();
-                                operateLog.tmdName = item.GetProperty("name").ToString();
-                                operateLog.operateDescribe = $"{tmdName}【{tmdId}】醍摩豆账号和{itemUser.name}【{itemUser.RowKey}】钉钉账户绑定成功";
-
+                                //保存操作记录
+                                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{tmdId}", tmdName: $"{tmdName}", msg: $"{tmdName}【{tmdId}】醍摩豆账号和{itemUser.name}【{itemUser.RowKey}】钉钉账户绑定成功", type: "tabledd-update", visitApi: "/common/login/binguser", funModel: "绑定");
                                 ddUserInfos.Add(itemUser);
                             }
                         }
 
                         var dingDingUserInfos = await _azureStorage.UpdateAll<DingDingUserInfo>(ddUserInfos);
-                        await _azureStorage.Save<OperateLog>(operateLog); //保存操作记录
+
 
                         return Ok(new { state = 200, ddUsers = dingDingUserInfos });
                     }
                     else return Ok(new { state = 400, message = "该手机没有注册提莫信息" });
                 }
                 else return Ok(new { state = responseMessage.StatusCode });
-
             }
             catch (Exception ex)
             {
@@ -1020,16 +602,6 @@ namespace TEAMModeBI.Controllers
                     }
                     else
                     {
-                        //操作记录
-                        OperateLog operateLog = new OperateLog();
-                        string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                        operateLog.PartitionKey = "OperateLog-BI";
-                        operateLog.RowKey = blobOrTable;
-                        operateLog.recordID = blobOrTable;
-                        operateLog.platformSource = "BI";
-                        operateLog.visitApi = "/common/login/get-ddinfo";
-                        operateLog.operateTime = DateTime.Now;
-
                         HttpClient httpClient = _http.CreateClient();
                         string url = _configuration.GetValue<string>("HaBookAuth:CoreId:userinfo");
                         HttpResponseMessage responseMessage = await httpClient.PostAsJsonAsync(url, moile);
@@ -1040,29 +612,27 @@ namespace TEAMModeBI.Controllers
                             if (temp.Length > 0)
                             {
                                 List<JsonElement> itemjson = temp.ToObject<List<JsonElement>>();
+                                string tmdId = null;
+                                string tmdName = null;
                                 foreach (var item in itemjson)
                                 {
-                                    var tmdId = item.GetProperty("id").ToString();
-                                    var tmdName = item.GetProperty("name").ToString();
-                                    itemUser.tmdId = tmdId;
-                                    itemUser.tmdName = tmdName;
+                                    tmdId = item.GetProperty("id").ToString();
+                                    tmdName = item.GetProperty("name").ToString();
+                                    itemUser.tmdId = tmdId?.ToString();
+                                    itemUser.tmdName = tmdName?.ToString();
                                     itemUser.tmdMobile = item.GetProperty("mobile").ToString();
                                     itemUser.picture = item.GetProperty("picture").ToString();
                                     itemUser.mail = item.GetProperty("mail").ToString();
                                     roles = !string.IsNullOrEmpty($"{itemUser.roles}") ? new List<string>(itemUser.roles.Split(",")) : new List<string>();
                                     permissions = !string.IsNullOrEmpty($"{itemUser.permissions}") ? new List<string>(itemUser.permissions.Split(",")) : new List<string>();
 
-                                    operateLog.operateType = "修改";
-                                    operateLog.funModule = "钉钉绑定";
-                                    operateLog.tmdId = item.GetProperty("id").ToString();
-                                    operateLog.tmdName = item.GetProperty("name").ToString();
-                                    operateLog.operateDescribe = $"{tmdName}【{tmdId}】醍摩豆账号和{itemUser.name}【{itemUser.RowKey}】钉钉账户绑定成功";
-
                                     ddUserInfos.Add(itemUser);
                                 }
 
                                 ddUserInfos = await _azureStorage.UpdateAll<DingDingUserInfo>(ddUserInfos);
-                                await _azureStorage.Save<OperateLog>(operateLog); //保存操作记录
+
+                                //保存操作记录
+                                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: tmdId?.ToString(), tmdName: tmdName?.ToString(), msg: $"{tmdName}【{tmdId}】醍摩豆账号和{itemUser.name}【{itemUser.RowKey}】钉钉账户绑定成功", type: "tabledd-update", visitApi: "/common/login/get-ddinfo", funModel: "绑定");
                             }
                             else return Ok(new { state = 400, message = "该手机没有注册醍摩豆账号信息" });
                         }

+ 15 - 28
TEAMModeBI/Controllers/OperateRecord/OperateLogController.cs

@@ -11,6 +11,8 @@ using TEAMModelOS.Models;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Models.Cosmos.BI;
 using System.Text;
+using TEAMModelOS.SDK.Models.Table;
+using TEAMModelOS.SDK.Helper.Common.TableHelper;
 
 namespace TEAMModeBI.Controllers.OperateRecord
 {
@@ -39,27 +41,24 @@ namespace TEAMModeBI.Controllers.OperateRecord
         {
             try
             {
+                jsonElement.TryGetProperty("single", out JsonElement single);
                 jsonElement.TryGetProperty("startDate", out JsonElement startDate);
                 jsonElement.TryGetProperty("endDate", out JsonElement endDate);
+                jsonElement.TryGetProperty("platform", out JsonElement platform);
 
                 List<OperateLog> operateLogs = null;
-
                 StringBuilder tableSql = new StringBuilder();
 
+                if (!string.IsNullOrEmpty($"{single}"))
+                    tableSql.Append($"RowKey {QueryComparisons.Equal} '{single}' ");
                 if (!string.IsNullOrEmpty($"{startDate}"))
-                {
-                    operateLogs = await _azureStorage.QueryWhereString<OperateLog>($"RowKey {QueryComparisons.GreaterThanOrEqual} '{startDate}'");
-                }
-                else if (!string.IsNullOrEmpty($"{startDate}") && !string.IsNullOrEmpty($"{endDate}"))
-                {
-                    operateLogs = await _azureStorage.QueryWhereString<OperateLog>($"RowKey {QueryComparisons.GreaterThanOrEqual} '{startDate}' {TableOperators.And} RowKey {QueryComparisons.LessThanOrEqual} '{endDate}'");
-                }
-                else
-                {
-                    operateLogs = await _azureStorage.QueryWhereString<OperateLog>();
-                    //operateLogs = await _azureStorage.FindListByDict<OperateLog>(dic);
-                }
+                    tableSql.Append(!string.IsNullOrEmpty(tableSql.ToString()) ? $" {TableOperators.And} RowKey {QueryComparisons.GreaterThanOrEqual} '{startDate}' " : $"RowKey {QueryComparisons.GreaterThanOrEqual} '{startDate}' ");
+                if (!string.IsNullOrEmpty($"{endDate}"))
+                    tableSql.Append(!string.IsNullOrEmpty(tableSql.ToString()) ? $" {TableOperators.And} RowKey {QueryComparisons.LessThanOrEqual} '{endDate}' " : $" RowKey { QueryComparisons.LessThanOrEqual} '{endDate}' ");
+                if(!string.IsNullOrEmpty($"{platform}"))
+                    tableSql.Append(!string.IsNullOrEmpty(tableSql.ToString()) ? $" {TableOperators.And} platform {QueryComparisons.Equal} '{platform}' " : $" platform {QueryComparisons.Equal} '{platform}' ");
 
+                operateLogs = await _azureStorage.QueryWhereString<OperateLog>(tableSql.ToString());
                 return Ok(new { state = 200, operateLogs });
             }
             catch (Exception ex)
@@ -85,18 +84,6 @@ namespace TEAMModeBI.Controllers.OperateRecord
                 jsonElement.TryGetProperty("endDate", out JsonElement endDate);
                 jsonElement.TryGetProperty("rowKey", out JsonElement rowKey);
 
-                //操作记录
-                OperateLog operateLog = new OperateLog();
-                string blobOrTable = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
-                operateLog.PartitionKey = "OperateLog-BI";
-                operateLog.RowKey = blobOrTable;
-                operateLog.recordID = blobOrTable;
-                operateLog.platformSource = "BI";
-                operateLog.tmdId = $"{_tmdId}";
-                operateLog.tmdName = $"{_tmdName}";
-                operateLog.visitApi = "/operatelog/del-operatelogbydate";
-                operateLog.operateTime = DateTime.Now;
-
                 //var temp = await _azureStorage.Delete<OperateLog>(partitionKey: "OperateLog-BI", rowKey: $"{startDate}");  //删除单个
                 StringBuilder operateStr = new StringBuilder($"{_tmdName}【{_tmdId}】账户删除操作记录,");
                 StringBuilder tableStrWhere = new StringBuilder();
@@ -112,8 +99,9 @@ namespace TEAMModeBI.Controllers.OperateRecord
                 }
                 var temp = await _azureStorage.DeleteStringWhere<OperateLog>(rowKey: tableStrWhere.ToString());
 
-                operateLog.operateDescribe = operateStr.ToString();
-                await _azureStorage.Save<OperateLog>(operateLog); //保存操作记录
+                //保存操作记录
+                await OperateLogHelper.SaveTableLog(_azureStorage, platform: "BI", tmdId: $"{_tmdId}", tmdName: $"{_tmdName}", msg: operateStr?.ToString(), type: "operatelog-del", visitApi: "/operatelog/del-operatelogbydate", funModel: "日志");
+
                 if (temp.Count > 0)
                 {
                     return Ok(new { state = 200 });
@@ -125,7 +113,6 @@ namespace TEAMModeBI.Controllers.OperateRecord
                 await _dingDing.SendBotMsg($"BI, {_option.Location} /operatelog/del-operatelogbydate  {ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
                 return BadRequest();
             }
-
         }
 
 

+ 165 - 0
TEAMModeBI/Controllers/Product/ProductStatisController.cs

@@ -0,0 +1,165 @@
+using Azure.Cosmos;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Models;
+
+namespace TEAMModeBI.Controllers.Product
+{
+    [Route("productstatis")]
+    [ApiController]
+    public class ProductStatisController : ControllerBase
+    {
+        //数据容器
+        private readonly AzureCosmosFactory _azureCosmos;
+        //钉钉提示信息
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+
+        public ProductStatisController(AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option) 
+        {
+            _azureCosmos = azureCosmos;
+            _dingDing = dingDing;
+            _option = option?.Value;
+        }
+
+        /// <summary>
+        /// 统计模组数量
+        /// </summary>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-productsum")]
+        public async Task<IActionResult> GetProductSum()
+        {
+            var cosmosClient = _azureCosmos.GetCosmosClient();
+            List<ProductStatis> productStatis = new List<ProductStatis>();
+            await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: $"SELECT c.prodinfo FROM c",requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("ProductSum") }))
+            {
+                using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                {
+                    foreach (var itemCount in json.RootElement.GetProperty("Documents").EnumerateArray())
+                    {
+                        List<SchoolProductSumProdInfo> prodInfo = itemCount.GetProperty("prodinfo").ToObject<List<SchoolProductSumProdInfo>>();
+                        foreach (var tempProdInfo in prodInfo)
+                        {
+                            ProductStatis tempPerod = productStatis.Find(x => x.prodName.Equals(tempProdInfo.prodName));
+                            if (!string.IsNullOrEmpty($"{tempPerod}"))
+                            {
+                                tempPerod.Count += 1;
+                            }
+                            else
+                            {
+                                ProductStatis tempProd = new ProductStatis()
+                                {
+                                    prodCode = tempProdInfo.prodCode,
+                                    prodName = tempProdInfo.prodName,
+                                    dataType = tempProdInfo.dataType,
+                                    Count = 1,
+                                };
+                                productStatis.Add(tempProd);
+                            }
+                        }
+                    }
+                }
+
+                //if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                //{
+                //    var accounts = json.RootElement.GetProperty("Documents").EnumerateArray();
+                //    while (accounts.MoveNext())
+                //    {
+                //        JsonElement account = accounts.Current;
+                //        List<SchoolProductSumProdInfo> prodInfo = account.GetProperty("prodinfo").ToObject<List<SchoolProductSumProdInfo>>();
+                //        foreach (var tempProdInfo in prodInfo)
+                //        {
+                //            ProductStatis tempPerod = productStatis.Find(x => x.prodName.Equals(tempProdInfo.prodName));
+                //            if (!string.IsNullOrEmpty($"{tempPerod}"))
+                //            {
+                //                tempPerod.Count += 1;
+                //            }
+                //            else
+                //            {
+                //                ProductStatis tempProd = new ProductStatis()
+                //                {
+                //                    prodCode = tempProdInfo.prodCode,
+                //                    prodName = tempProdInfo.prodName,
+                //                    dataType = tempProdInfo.dataType,
+                //                    Count = 1,
+                //                };
+                //                productStatis.Add(tempProd);
+                //            }
+                //        }
+                //    }
+                //}
+            }
+            return Ok(new { sate = 200, productStatis });
+        }
+
+        /// <summary>
+        /// 单个学校的模组
+        /// </summary>
+        /// <param name="jsonElement"></param>
+        /// <returns></returns>
+        [HttpPost("get-productsumid")]
+        public async Task<IActionResult> GetProductSchoolId(JsonElement jsonElement)
+        {
+            if (!jsonElement.TryGetProperty("schoolCode", out JsonElement id)) return BadRequest();
+
+            List<ProductStatis> productStatis = new List<ProductStatis>();
+
+            var cosmosClient = _azureCosmos.GetCosmosClient();
+            await foreach (var item in cosmosClient.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: $"SELECT c.id,c.prodinfo FROM c where c.id='{id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("ProductSum") }))
+            {
+                using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                foreach (var itemCount in json.RootElement.GetProperty("Documents").EnumerateArray())
+                {
+                    List<SchoolProductSumProdInfo> prodInfo = itemCount.GetProperty("prodinfo").ToObject<List<SchoolProductSumProdInfo>>();
+                    foreach (var tempProdInfo in prodInfo)
+                    {
+                        ProductStatis tempPerod = productStatis.Find(x => x.prodName.Equals(tempProdInfo.prodName));
+                        if (!string.IsNullOrEmpty($"{tempPerod}"))
+                        {
+                            tempPerod.Count += 1;
+                        }
+                        else
+                        {
+                            ProductStatis tempProd = new ProductStatis()
+                            {
+                                prodCode = tempProdInfo.prodCode,
+                                prodName = tempProdInfo.prodName,
+                                dataType = tempProdInfo.dataType,
+                                Count = 1,
+                            };
+                            productStatis.Add(tempProd);
+                        }
+                    }
+                }
+            }
+
+            return Ok(new { state = 200, productStatis }) ;
+        }
+
+
+        public record ProductStatis 
+        {
+            public string prodCode { get; set; }
+
+            public string prodName { get; set; }
+
+            public string dataType { get; set; }
+
+            public long Count { get; set; }
+
+
+        }
+         
+    }
+}

+ 63 - 1
TEAMModeBI/appsettings.json

@@ -6,5 +6,67 @@
       "Microsoft.Hosting.Lifetime": "Information"
     }
   },
-  "AllowedHosts": "*"
+  "AllowedHosts": "*",
+  "DingDingAuth": {
+    "Agentld": "1290158212",
+    "appKey": "dingrucgsnt8p13rfbgd",
+    "appSecret": "Gyx_N57yZslhQOAhAPlvmCwOp_qTm1DScKbd5OoOE0URAW4eViYA2Sk_ZxKb-8WG",
+    "getuserinfo_bycode": "https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=xxx&timestamp=xxx&signature=xxx"
+  },
+  "Option": {
+    "Location": "China-Dep",
+    "LocationNum": "1",
+    "HostName": "localhost:5001",
+    "AllowedHosts": [ "localhost", "*.teammodel.cn", "*.teammodel.net", "*.habookaclass.biz", "test" ],
+    "Issuer": "www.teammodel.cn",
+    "JwtSecretKey": "fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA=",
+    "Exp": 86400,
+    "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",
+    "HttpTrigger": "https://teammodelosfunction-test.chinacloudsites.cn/api/"
+    //"HttpTrigger": "http://localhost:7071/api/"
+  },
+  "Azure": {
+    //
+    "Storage": {
+      "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelstorage;AccountKey=Yq7D4dE6cFuer2d2UZIccTA/i0c3sJ/6ITc8tNOyW+K5f+/lWw9GCos3Mxhj47PyWQgDL8YbVD63B9XcGtrMxQ==;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==;"
+    },
+    "Redis": {
+      "ConnectionString": "52.130.252.100:6379,password=habook,ssl=false,abortConnect=False,writeBuffer=10240"
+      //"ConnectionString": "106.12.23.251: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", //消息
+      "NoticeTask": "dep-notice-task", //消息
+      "ItemCondQueue": "dep-itemcond" //队列消息
+    }
+  },
+  "HaBookAuth": {
+    "CoreId": {
+      "userinfo": "https://api2.teammodel.cn/Oauth2/GetUserInfos"
+    },
+    "sendSMS": {
+      "smstion": "https://api2.teammodel.net/service/sandsms/pin", //验证醍摩豆账户是否存在,存在并发送验证码, 失败就不发送验证码
+      "verifiysms": "https://api2.teammodel.net/service/verifiy/pin" //验证短信验证码信息
+    },
+    "Account": "https://account.teammodel.cn",
+    "CoreAPI": "https://api2.teammodel.cn",
+    "CoreService": {
+      "clientID": "c7317f88-7cea-4e48-ac57-a16071f7b884",
+      "clientSecret": "kguxh:V.PLmxBdaI@jnrTrDSth]A3346",
+      "deviceinfo": "https://api2.teammodel.cn/oauth2/getdeviceinfos",
+      "sendnotification": "https://api2.teammodel.net/service/sendnotification",
+      "getnotification": "https://api2.teammodel.net/service/getnotification",
+      "delnotification": "https://api2.teammodel.net/service/delnotification"
+    }
+  },
+  "CustomParam": {
+    "SiteScope": "continent" // 站点范围  continent 大路站  international 国际站
+  }
 }

+ 58 - 6
TEAMModelFunction/ScsApisHttpTrigger.cs

@@ -42,12 +42,64 @@ namespace TEAMModelFunction
             _azureRedis = azureRedis;
             _thirdApisService = thirdApisService;
         }
-        [FunctionName("HttpExample")]
-        public static async Task<IActionResult> Run(
-     [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
-     ILogger log)
-        {
-            return new OkObjectResult(new { data="1"});
+
+        /// <summary>
+        /// 数据推送接口
+        /// </summary>
+        /// <param name="req"></param>
+        /// <param name="log"></param>
+        /// <returns></returns>
+        [FunctionName("KnowledgeChange")]
+        public async Task<IActionResult> KnowledgeChange([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log) {
+            string data = await new StreamReader(req.Body).ReadToEndAsync();
+           var  json = JsonDocument.Parse(data).RootElement;
+            List<OldNew> old_new = null;
+            string school = null;
+            if (json.TryGetProperty("school", out JsonElement _school))
+            {
+                school = _school.GetString();
+            }
+            if (json.TryGetProperty("old_new", out JsonElement _old_new))
+            {
+                old_new = _old_new.ToObject<List<OldNew>>();
+            }
+            if (old_new.IsNotEmpty() && !string.IsNullOrWhiteSpace(school))
+            {
+                foreach (var on in old_new)
+                {
+                    List<ItemInfo> items = new List<ItemInfo>();
+                    string sql = $"select value(c) from c    where array_contains(c.knowledge,'{on._old}') ";
+                    await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ItemInfo>
+                        (queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{_school}") }))
+                    {
+                        items.Add(item);
+                    }
+
+                    items.ForEach(item => {
+                        //修改知识点
+                        if (!string.IsNullOrEmpty(on._new))
+                        {
+                            for (int i = 0; i < item.knowledge.Count; i++)
+                            {
+                                if (item.knowledge[i].Equals(on._old))
+                                {
+                                    item.knowledge[i] = on._new;
+                                }
+                            }
+                        }
+                        else
+                        {
+                            //表示删除知识点
+                            item.knowledge.RemoveAll(x => x.Equals(on._old));
+                        }
+                    });
+                    foreach (var item in items)
+                    {
+                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(item, item.id, new PartitionKey(item.code));
+                    }
+                }
+            }
+            return new OkResult();
         }
         /// <summary>
         /// 数据推送接口

+ 1 - 1
TEAMModelOS.SDK/DI/HttpTrigger/HttpTrigger.cs

@@ -36,7 +36,7 @@ namespace TEAMModelOS.SDK.DI
             string domain = "";
             if (location.Equals("China-Dep"))
             {
-                domain = keys[1];
+                domain = keys[0];
             }
             else if (location.Equals("China-Test"))
             {

+ 46 - 0
TEAMModelOS.SDK/Helper/Common/TableHelper/OperateLogHelper.cs

@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Models.Table;
+
+namespace TEAMModelOS.SDK.Helper.Common.TableHelper
+{
+    public class OperateLogHelper
+    {
+        /// <summary>
+        /// 保存操作日志
+        /// </summary>
+        /// <param name="_azureStorage"></param>
+        /// <param name="platform">日志平台:BI 、 IES5</param>
+        /// <param name="tmdId">醍摩豆ID</param>
+        /// <param name="tmdName">醍摩豆名称</param>
+        /// <param name="msg">操作描述</param>
+        /// <param name="type">日志类型: school-update school-del    名词-动词组合方式</param>
+        /// <param name="visitApi">访问接口</param>
+        /// <param name="funModel">模块名称 存中文</param>
+        /// <param name="scope">使用范围  private school</param>
+        /// <param name="owner">数据归属  学校编码或者醍摩豆id</param>
+        /// <param name="leve">日志等级,1普通 2重要 3非常重要</param>
+        /// <returns></returns>
+        public static async Task SaveTableLog(AzureStorageFactory _azureStorage, string platform, string tmdId, string tmdName, string msg, string type, string visitApi,string funModel = null, string scope = null, string owner = null, int leve = 1)
+        {
+            OperateLog operateLog = new OperateLog();
+            operateLog.PartitionKey = $"Log-{platform}";
+            operateLog.RowKey = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
+            operateLog.platform = platform;
+            operateLog.tmdId = tmdId;
+            operateLog.tmdName = tmdName;
+            operateLog.msg = msg;
+            operateLog.type = type;
+            operateLog.visitApi = visitApi;
+            operateLog.funModule = $"{funModel}";
+            operateLog.scope = $"{scope}";
+            operateLog.owner = $"{owner}";
+            operateLog.leve = leve;
+
+            await _azureStorage.Save<OperateLog>(operateLog);
+        }
+    }
+}

+ 55 - 0
TEAMModelOS.SDK/Helper/Common/ValidatorHelper/ValidatorHelper.cs

@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+
+namespace TEAMModelOS.SDK
+{
+    public static class ValidatorHelper
+    {
+        public static ValidResult IsValid(this Object obj) {
+            ValidResult result = new ValidResult();
+            try {
+                var context = new ValidationContext(obj, null, null);
+                var results = new List<ValidationResult>();
+                if (Validator.TryValidateObject(obj, context, results, true))
+                {
+                    result.isVaild = true;
+                }
+                else
+                {
+                    List<(string msg,  string name)> error = new List<(string msg, string name)>();
+                    foreach (var validationResult in results)
+                    {
+                        if (validationResult.MemberNames != null && validationResult.MemberNames.Count()>0) {
+                            validationResult.MemberNames.ToList().ForEach(x => {
+                                error.Add((validationResult.ErrorMessage, x));
+                            });
+                        }
+                    }
+                    result.errors = new Dictionary<string, IEnumerable<string>>();
+                    error.GroupBy(x => x.name).ToList().ForEach(z => {
+                        result.errors.Add(z.Key, z.ToList().Select(x => x.msg));
+                    });
+                }
+            } catch (Exception ex) {
+                result.isVaild = false;
+                result.errors = new Dictionary<string, IEnumerable<string>>();
+                result.errors.Add("InternalError", new List<string> { ex.Message });
+            }
+            return result;
+        }
+
+        
+    }
+    public class ValidResult
+    {
+        public string traceId { get; set; } = Guid.NewGuid().ToString();
+        public string type { get; set; } = "https://tools.ietf.org/html/rfc7231#section-6.5.1";
+        public string title { get; set; } = "One or more validation errors occurred.";
+        public int status { get; set; } = 400;
+        public bool isVaild { get; set; }
+        public Dictionary<string, IEnumerable<string>> errors { get; set; }
+    }
+}

+ 0 - 58
TEAMModelOS.SDK/Models/Cosmos/BI/OperateLog.cs

@@ -1,58 +0,0 @@
-using Microsoft.Azure.Cosmos.Table;
-using System;
-using System.Collections.Generic;
-using System.Text;
-using TEAMModelOS.SDK.Context.Attributes.Azure;
-
-namespace TEAMModelOS.SDK.Models.Cosmos.BI
-{
-    [TableName(Name = "OperateLog")]
-    public class OperateLog: TableEntity
-    {
-
-        /// <summary>
-        /// Blob和
-        /// </summary>
-        public string recordID { get; set; }
-
-        /// <summary>
-        /// 平台;BI 、 IES5
-        /// </summary>
-        public string platformSource { get; set; }
-
-        /// <summary>
-        /// 醍摩豆ID
-        /// </summary>
-        public string tmdId { get; set; }
-
-        /// <summary>
-        /// 醍摩豆名称
-        /// </summary>
-        public string tmdName { get; set; }
-
-        /// <summary>
-        /// 操作描述
-        /// </summary>
-        public string operateDescribe { get; set; }
-
-        /// <summary>
-        /// 操作类型 0查询 1增加 2修改 3删除 4登录
-        /// </summary>
-        public string operateType { get; set; }
-
-        /// <summary>
-        /// 功能模块
-        /// </summary>
-        public string funModule { get; set; }
-
-        /// <summary>
-        /// 访问的Api
-        /// </summary>
-        public string visitApi { get; set; }
-
-        /// <summary>
-        /// 操作时间
-        /// </summary>
-        public DateTime operateTime { get; set; }
-    }
-}

+ 7 - 1
TEAMModelOS.SDK/Models/Cosmos/School/Knowledge.cs

@@ -39,7 +39,13 @@ namespace TEAMModelOS.SDK.Models
         public List<Block> blocks { get; set; } = new List<Block>();
 
     }
-
+    public class OldNew
+    {
+        [Required(ErrorMessage = "_old 必须设置")]
+        public string _old { get; set; }
+        [Required(ErrorMessage = "_new 必须设置")]
+        public string _new { get; set; }
+    }
     public class Block { 
         public string name { get; set; }
         public List<string> points { get; set; }

+ 64 - 0
TEAMModelOS.SDK/Models/Table/OperateLog.cs

@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using TEAMModelOS.SDK.Context.Attributes.Azure;
+using Microsoft.Azure.Cosmos.Table;
+
+namespace TEAMModelOS.SDK.Models.Table
+{
+    [TableName(Name = "OperateLogs")]
+    public class OperateLog : TableEntity
+    {
+        /// <summary>
+        /// 日志平台:BI 、 IES5
+        /// </summary>
+        public string platform { get; set; }
+
+        /// <summary>
+        /// 日志等级,1普通 2重要 3非常重要
+        /// </summary>
+        public int leve { get; set; } = 1;
+
+        /// <summary>
+        /// 醍摩豆ID
+        /// </summary>
+        public string tmdId { get; set; }
+
+        /// <summary>
+        /// 醍摩豆名称
+        /// </summary>
+        public string tmdName { get; set; }
+
+        /// <summary>
+        /// 操作描述
+        /// </summary>
+        public string msg { get; set; }
+
+        /// <summary>
+        /// 日志类型: school-update school-del    名词-动词组合方式
+        /// </summary>
+        public string type { get; set; }
+
+        /// <summary>
+        /// 模块名称 存中文
+        /// </summary>
+        public string funModule { get; set; }
+
+        /// <summary>
+        /// 访问接口
+        /// </summary>
+        public string visitApi { get; set; }
+
+        /// <summary>
+        /// 使用范围  private school
+        /// </summary>
+        public string scope { get; set; }
+
+        /// <summary>
+        /// 数据归属  学校编码或者醍摩豆id
+        /// </summary>
+        public string owner { get; set; }
+
+
+    }
+}

+ 23 - 7
TEAMModelOS/ClientApp/public/index.html

@@ -7,8 +7,26 @@
 		<link rel="icon" href="<%= BASE_URL %>favicon.ico">
 		<link id="theme" type="text/css" rel="stylesheet" href="<%= BASE_URL %>theme/dark-theme.css">
 		<!-- <link rel="stylesheet" href="//unpkg.com/view-design/dist/styles/iview.css"> -->
-		
 		<title></title>
+		<script>
+		MathJax = {
+		  loader: {load: ["input/tex", "output/svg"]},
+		  // mml:{
+			 //  forceReparse:true
+		  // },
+		  tex: {
+			inlineMath: [['$', '$'], ['\\(', '\\)']],
+			displayMath: [["$$", "$$"], ["\\[", "\\]"]]
+		  },
+		  svg: {
+			fontCache: 'local'
+			},
+			skipTags: ["script", "noscript", "style", "textarea", "pre", "code", "a"] //避开某些标签
+		};
+		</script>
+		<script type="text/javascript" id="MathJax-script" async
+		  src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-svg.js">
+		</script>
 		<script>
 			let cloudSetting = localStorage.getItem('cloudSetting')
 			if (cloudSetting) {
@@ -25,12 +43,10 @@
 			<strong>IES5</strong>
 		</noscript>
 		<div id="app"></div>
-		<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.min.js"></script>
-		<script src="https://cdn.bootcdn.net/ajax/libs/echarts/4.2.1/echarts.min.js"></script>
-		<script src="https://cdn.bootcdn.net/ajax/libs/view-design/4.2.0/iview.min.js"></script>
-		<script src="https://cdn.bootcdn.net/ajax/libs/fabric.js/451/fabric.min.js"></script>
-		<script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.2.0/vue-router.min.js"></script>
-		<!-- <script src="https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.1/xlsx.min.js"></script> -->
+		<script src="https://teammodelstorage.blob.core.chinacloudapi.cn/0-public/js/vue.min.js"></script>
+		<script src="https://teammodelstorage.blob.core.chinacloudapi.cn/0-public/js/iview.min.js"></script>
+		<script src="https://teammodelstorage.blob.core.chinacloudapi.cn/0-public/js/fabric.min.js"></script>
+		<script src="https://teammodelstorage.blob.core.chinacloudapi.cn/0-public/js/vue-router.min.js"></script>
 	</body>
 
 </html>

+ 2 - 2
TEAMModelOS/ClientApp/src/common/AbilityUpload.vue

@@ -202,7 +202,7 @@
 				for (let i = 0; i < list.length; i++) {
 					let file = list[i]
 					try {
-						let blobFile = await containerClient.upload(file, path, {
+						let blobFile = await containerClient.upload(file, { path:path }, {
 							onProgress: function(e) {
 								that.$set(that.progressArr, i, parseInt(e.loadedBytes * 100 / file.size))
 							}
@@ -232,7 +232,7 @@
 						let n = blobJson.name.substring(0, blobJson.name.lastIndexOf('.'))
 						let dataUrl = await this.$jsFn.createVideoPoster(fileFullUrl.url,blobJson.name)
 						let f = this.$jsFn.dataURLtoFile(dataUrl, n + '.png')
-						let blobFile = await containerClient.upload(f, path);
+						let blobFile = await containerClient.upload(f, { path:path });
 						r(blobFile)
 					} catch (e) {
 						r(e)

+ 1 - 1
TEAMModelOS/ClientApp/src/common/BaseUpload.vue

@@ -100,7 +100,7 @@
 					let file = list[i]
 					promiseArr.push(new Promise(async (r,j) => {
 						try{
-							let blobFile = await containerClient.upload(file, this.prefix,{
+							let blobFile = await containerClient.upload(file, { path:this.prefix },{
 								onProgress: function (e) {
 									that.$set(that.progressArr,i,parseInt(e.loadedBytes * 100 / file.size))
 								}

+ 1 - 1
TEAMModelOS/ClientApp/src/components/homework/BaseHwForm.vue

@@ -453,7 +453,7 @@ export default {
         let promiseArr = []
         files.forEach(file => {
           promiseArr.push(new Promise((r, j) => {
-            blobClient.upload(file, 'homework/' + data.id, undefined, false).then(async blobFile => {
+            blobClient.upload(file, { path:'homework/' + data.id,checkSize:false }, undefined).then(async blobFile => {
               // 如果上传的是视频文件 则需要获取视频的时长信息和MD5信息
               blobFile.duration = blobFile.type === 'video' ? await this.$tools.getVideoDuration(file) : 0
               blobFile.md5 = this.$tools.convertFileMD5ToString(blobFile.md5)

+ 17 - 11
TEAMModelOS/ClientApp/src/components/mark/MarkCanvas.vue

@@ -127,7 +127,7 @@ export default {
                 let nodes = _this.tr.nodes()
                 if (_this.mouseStatus == 'move' && nodes.length == 0) _this.mouseStatus = _this.moveBefore
             })
-            
+
             this.markLayer.add(this.img)
             this.stage.add(this.markLayer)
             this.img.zIndex(999)
@@ -756,15 +756,21 @@ export default {
 
         /* 保存批注 */
         saveAsImg() {
-            return new Promise(async (r, j) => {
-                let compressImg = await this.$editorTools.compressImg(this.stage.toDataURL(),
-                    this.stage.attrs.width, this.stage.attrs.height)
-                r({
-                    base64: compressImg,
-                    width: this.stage.attrs.width,
-                    height: this.stage.attrs.height
-                })
-            })
+            // return new Promise(async (r, j) => {
+            //     let compressImg = await this.$editorTools.compressImg(this.stage.toDataURL(),
+            //         this.stage.attrs.width, this.stage.attrs.height)
+            //     r({
+            //         base64: compressImg,
+            //         width: this.stage.attrs.width,
+            //         height: this.stage.attrs.height
+            //     })
+            // })
+            //批注单独存图片,不用进行图片压缩
+            return {
+                base64: this.stage.toDataURL(),
+                width: this.stage.attrs.width,
+                height: this.stage.attrs.height
+            }
         },
         initStage() {
             //创建画布
@@ -870,7 +876,7 @@ export default {
                 console.log('开始画图')
                 this.drawImg()
             },
-            deep:true
+            deep: true
         },
         status: {
             handler(n, o) {

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

@@ -366,7 +366,10 @@ export default {
                     let promiseArr = []
                     this.uploadList.map(item => {
                         promiseArr.push(new Promise((r, j) => {
-                            blobTool.upload(item, path, {}, false).then(res => {
+                            blobTool.upload(item, {
+                                path,
+                                checkSize: false
+                            }).then(res => {
                                 res.prime = false //学生端默认false,教师端为true,表示是主要文件,会上传到区级
                                 r(res)
                             })

+ 1 - 1
TEAMModelOS/ClientApp/src/components/student-web/SettingView/Setting.vue

@@ -625,7 +625,7 @@ export default {
             if(this.student) {
                 let blobInfo = await this.$api.blob.blobSasRCW({name: this.userInfo.azp, role: "student"})
                 let blobTool = new BlobTool(blobInfo.url, this.userInfo.azp, '?' + blobInfo.sas, 'school')
-                blobTool.upload(file, 'avatar', {}, false).then(
+                blobTool.upload(file, {path:'avatar', checkSize: false}).then(
                     res => {
                         console.log(res.url);
                         let stuParam = {

+ 3 - 5
TEAMModelOS/ClientApp/src/components/syllabus/DragTree.vue

@@ -23,7 +23,7 @@
 						<Icon type="ios-remove-circle-outline" style="margin-right: 5px;" size="16" />
 						<span style="color: #9f9f9f;font-size: 12px;margin-right: 20px;"  @click="onIgnoreShare(data)">{{ $t('syllabus.ignoreChapter') }}</span>
 					</span> -->
-					<span class="custom-tree-tools" v-if="((hasEditAuth(data) || $access.can('admin.*|Syllabus_Edit')) && !inShareView && Boolean(editable)) && !inSchoolAbility">
+					<span class="custom-tree-tools" v-if="((hasEditAuth(data) || $access.can('admin.*|syllabus-upd')) && !inShareView && Boolean(editable)) && !inSchoolAbility">
 						<Icon type="md-create" size="16" :title="$t('syllabus.tree.edit')" @click="onEditItem(node,data,$event)" />
 						<Icon type="md-trash" size="16" :title="$t('syllabus.tree.remove')" @click="remove(node,data)" v-if="!isFirstLevel(data) ||  (canDeleteChapter && isFirstLevel(data))"/>
 						<Icon type="md-add" size="16" :title="$t('syllabus.tree.add')" @click="onAddNode(node,data,$event)" />
@@ -771,13 +771,13 @@
 					// 判断是否为一级节点,如果是二级节点则需要拿对应的一级节点去做判断
 					let chapterId = nodeData.pid === this.volume.id ? nodeData.id : this.getChapterIdById(nodeData.id)
 					let chapterNode = this.treeDatas.find(i => i.id === chapterId)
-					return (!this.isSchool && !this.inShareView) || this.$access.can('admin.*|Syllabus_Edit') || this.volume.auth.map(i => i.tmdid).includes(userId) || (chapterNode && chapterNode.auth && chapterNode.auth.length && chapterNode.auth.map(i => i.tmdid).includes(userId))
+					return (!this.isSchool && !this.inShareView) || this.$access.can('admin.*|syllabus-upd') || this.volume.auth.map(i => i.tmdid).includes(userId) || (chapterNode && chapterNode.auth && chapterNode.auth.length && chapterNode.auth.map(i => i.tmdid).includes(userId))
 				}
 			},
 			// 判断当前用户是否可以删除当前章节
 			canDeleteChapter(){
 				let userId = this.curTeammodelId
-				return this.$access.can('admin.*|Syllabus_Edit') || this.volume.auth.map(i => i.tmdid).includes(userId) || !this.isSchool
+				return this.$access.can('admin.*|syllabus-upd') || this.volume.auth.map(i => i.tmdid).includes(userId) || !this.isSchool
 			},
 			curCode() {
 				return this.isSchool ? this.$store.state.userInfo.schoolCode : this.curTeammodelId
@@ -800,7 +800,6 @@
 			// 监听课纲数据变化
 			treeData: {
 				handler: function(n, o) {
-					console.log(n);
 					// 以下为拼接树形数据以及册别数据
 					this.treeDatas = n.map(i => {
 						if(i.trees.length){
@@ -810,7 +809,6 @@
 							return {}
 						}
 					})
-					console.log(this.treeDatas);
 					this.getAllChild(this.treeDatas)
 					if(this.treeDatas.length){
 						this.$nextTick().then(() => {

+ 2 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/cusMgt.js

@@ -174,6 +174,8 @@ export default {
     setOk:'Set up successfully',
     setErr:'Failed to set up',
     uploadErr:'Failed to upload profile picture',
+    deleteGroup:'刪除分組',
+    delGroupContent:'確認刪除',
     setAvatarLabel:'Set Profile Picture',
     classStuErr:'Failure to obtain class list',
     

+ 1 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/researchCenter.js

@@ -4,5 +4,6 @@ export default{
         order: "次",
         part: "分",
         scienceScore: "Technological Interaction Index",
+        TScore: "教学应用",
     }
 }

+ 136 - 135
TEAMModelOS/ClientApp/src/locale/lang/en-US/stuAccount.js

@@ -1,141 +1,142 @@
 export default {
-  // table title
-  seatNo: 'Seat No.',
-  account: 'Account/Student ID',
-  stuName: 'Name',
-  classroomCode: 'Class',
-  classroomName: 'Classroom Name',
-  period: 'School System',
-  grade: 'Grade',
-  authStatus: 'Authorization Status',
-  password: 'Password',
-  abnormalStatus: 'Status Abnormal',
+	qrcode: '二維碼貼紙',
+	// table title
+	seatNo: 'Seat No.',
+	account: 'Account/Student ID',
+	stuName: 'Name',
+	classroomCode: 'Class',
+	classroomName: 'Classroom Name',
+	period: 'School System',
+	grade: 'Grade',
+	authStatus: 'Authorization Status',
+	password: 'Password',
+	abnormalStatus: 'Status Abnormal',
 
-  // Index.vue
-  menuAuth: 'Authorization Management',
-  importStu: 'Import List',
-  addStu: 'Add Student',
-  editInfo: 'Edit Information',
-  delStu: 'Delete Student',
-  searchHolder: 'Search',
-  periodHolder: 'Select School System',
-  gradeHolder: 'Select Grade',
-  classroomHolder: 'Select Class',
-  tips1: 'Please select the student that needs to be modified!',
-  tips2Title: 'Delete Student',
-  tips2Content1: 'Confirm delete',
-  tips2Content2: 'Account Information!',
-  tips2Content3: 'Confirm bulk delete',
-  tips2Content4: ' students',
-  tips3: 'Please select the students to be deleted!',
-  sltPdFirst:'Please select school system first',
-  sltGdFirst:'Please select grade level first',
-  noClass:'This grade has no class yet',
-  noRelClass:'Unrelated Classes',
-  resetPw:'Reset Password',
-  semYear:'Semester:',
-  delOk:'Deleted successfully',
-  delErr: 'Failed to delete',
-  isBottom:'This is the bottom',
-  edit:'Edit',
-  adminClass:'Admin Class',
-  teachClass:'Customized Class',
-  stuMgt:'Student Management',
-  filterNoClass:'Filter students who are not associated with any classes',
-  updClass:'Change Class',
-  sltStuLabel:'Selected Student:',
-  classLabel:'Class:',
-  
-  // AddStudent.vue
-  accountInfo: 'Account Information',
-  accountHolder: 'Please enter account information',
-  passwordInfo: 'Password',
-  passwordHolder: 'Please set your account password',
-  isSame: 'Same as account information',
-  stuName: 'Student Name',
-  stuNameHolder: 'Please enter student name',
-  stuSeatNo: 'Seat Number',
-  stuSeatNoHolder: 'Please set the seat number',
-  classroomInfo: 'Class',
-  classroomInfoHolder: 'Please select class',
-  newClassroom: 'Create a new class',
-  periodInfo: 'School System',
-  gradeInfo: 'Grade',
-  submitAccount: 'Create Account',
-  submitActive: 'Save',
-  chooseInfo: 'Select Item',
-  chooseNum: 'Total:',
-  numUnit: 'item',
-  academicYear: 'Academic Year',
-  noMatch:'No matching data yet',
-  stuIdErr:'Student account cannot be empty',
-  stuIdErr1: 'Student account format is a 4-12 digit number',
-  stuIdErr2: 'Duplicate Student Account Number',
-  setNoErr1:"Please set the student's class",
-  setNoErr2:'The seat number is repeated in the class',
-  sltStuTips:'Please select student first',
-  addOk:'Added successfully',
-  updOk:'Modified successfully',
-  addErr:'Failed to add',
-  updErr:'Failed to modify',
-  sltClassTips:'Please set the class',
-  setNoErr:'Student seat number cannot be empty',
-  classErr:"Please set the student's class",
-  pwErr:'Password cannot be empty',
-  nameErr:'Student name cannot be empty',
-  repeatErr:'Duplicate account or seat number',
+	// Index.vue
+	menuAuth: 'Authorization Management',
+	importStu: 'Import List',
+	addStu: 'Add Student',
+	editInfo: 'Edit Information',
+	delStu: 'Delete Student',
+	searchHolder: 'Search',
+	periodHolder: 'Select School System',
+	gradeHolder: 'Select Grade',
+	classroomHolder: 'Select Class',
+	tips1: 'Please select the student that needs to be modified!',
+	tips2Title: 'Delete Student',
+	tips2Content1: 'Confirm delete',
+	tips2Content2: 'Account Information!',
+	tips2Content3: 'Confirm bulk delete',
+	tips2Content4: ' students',
+	tips3: 'Please select the students to be deleted!',
+	sltPdFirst: 'Please select school system first',
+	sltGdFirst: 'Please select grade level first',
+	noClass: 'This grade has no class yet',
+	noRelClass: 'Unrelated Classes',
+	resetPw: 'Reset Password',
+	semYear: 'Semester:',
+	delOk: 'Deleted successfully',
+	delErr: 'Failed to delete',
+	isBottom: 'This is the bottom',
+	edit: 'Edit',
+	adminClass: 'Admin Class',
+	teachClass: 'Customized Class',
+	stuMgt: 'Student Management',
+	filterNoClass: 'Filter students who are not associated with any classes',
+	updClass: 'Change Class',
+	sltStuLabel: 'Selected Student:',
+	classLabel: 'Class:',
 
-  // ImportStudent.vue
-  importTitle: 'Import Student List',
-  importTips1: 'Drag the student account form file you want to import here',
-  importTips2: 'or ',
-  importTips3: 'click on the file icon to browse and upload a file',
-  importTips4: 'The open file has been deleted!',
-  importTips5: 'Incorrect file type',
-  importTips6: 'File:',
-  importTips7: 'is not an EXCEL file, please select a .xlsx or .xls file.',
-  importTips8: 'Error reading the file',
-  importTips9: 'Missing',
-  importTips10: ' information, please complete, then import!',
-  importTips11: 'File read successfully!',
-  importTips12: 'Please check if the form data is correct!',
-  importInfo1: 'Total Student Number:',
-  importInfo2: 'Repeated Account/Student ID:',
-  importInfo3: 'Repeated Seat Number:',
-  importInfo4: 'No corresponding classroom:',
-  importInfo5: 'The account already exists in the system:',
-  importInfo6: 'Can be imported:',
-  passwordTips: 'Items with no password found will default to the same password as the account/student ID',
-  submitList: 'Create Account',
-  lackAttr:'Incomplete Excel Column:',
-  noSetNo:'No Seat Number:',
-  gradeErr:'Grade Error:',
-  attrWarning:'Warning: Excel Column is incomplete!',
-  setNoWarning:'Warning: Seat number is repeated in Excel!',
-  idWarning:'Warning: Account/student ID is repeated in Excel!',
-  idFormatWarning:'Error:Student account format is a 4-12 digit number',
-  gradeWarning:'Warning: Error in grade',
-  setNoErr:"Error: Seat number has been repeated within the school",
-  downloadText:'(Download List Sample)',
-  idRepErr:'Account already exists, will overwrite the original account',
-  stuYearErr:"Student's academic year data is incorrect",
-  classYearErr:"Class's grade level is incorrect",
-  noFormatErr: 'Incorrect seat number format',
-  classFormatErr: 'Incorrect class format',
-  classNameErr: 'Class name abnormal',
-  importOk: 'Import successfully',
+	// AddStudent.vue
+	accountInfo: 'Account Information',
+	accountHolder: 'Please enter account information',
+	passwordInfo: 'Password',
+	passwordHolder: 'Please set your account password',
+	isSame: 'Same as account information',
+	stuName: 'Student Name',
+	stuNameHolder: 'Please enter student name',
+	stuSeatNo: 'Seat Number',
+	stuSeatNoHolder: 'Please set the seat number',
+	classroomInfo: 'Class',
+	classroomInfoHolder: 'Please select class',
+	newClassroom: 'Create a new class',
+	periodInfo: 'School System',
+	gradeInfo: 'Grade',
+	submitAccount: 'Create Account',
+	submitActive: 'Save',
+	chooseInfo: 'Select Item',
+	chooseNum: 'Total:',
+	numUnit: 'item',
+	academicYear: 'Academic Year',
+	noMatch: 'No matching data yet',
+	stuIdErr: 'Student account cannot be empty',
+	stuIdErr1: 'Student account format is a 4-12 digit number',
+	stuIdErr2: 'Duplicate Student Account Number',
+	setNoErr1: "Please set the student's class",
+	setNoErr2: 'The seat number is repeated in the class',
+	sltStuTips: 'Please select student first',
+	addOk: 'Added successfully',
+	updOk: 'Modified successfully',
+	addErr: 'Failed to add',
+	updErr: 'Failed to modify',
+	sltClassTips: 'Please set the class',
+	setNoErr: 'Student seat number cannot be empty',
+	classErr: "Please set the student's class",
+	pwErr: 'Password cannot be empty',
+	nameErr: 'Student name cannot be empty',
+	repeatErr: 'Duplicate account or seat number',
 
-  // Authorization.vue
-  authTitle: 'Service Authorization Management',
-  authTitle1: 'AClass One Learning Companion Service Authorization',
-  authDiscraption: 'Grant access to the Learning Companion App to students with TEAM Model IDs that are authorized to use the service.',
-  authCount: 'Total authorization number of school',
-  alreadyUse: 'Number of authorizations used today',
-  mayUse: 'Number of authorizations available',
-  authNum: 'Authorized use status of each school system',
+	// ImportStudent.vue
+	importTitle: 'Import Student List',
+	importTips1: 'Drag the student account form file you want to import here',
+	importTips2: 'or ',
+	importTips3: 'click on the file icon to browse and upload a file',
+	importTips4: 'The open file has been deleted!',
+	importTips5: 'Incorrect file type',
+	importTips6: 'File:',
+	importTips7: 'is not an EXCEL file, please select a .xlsx or .xls file.',
+	importTips8: 'Error reading the file',
+	importTips9: 'Missing',
+	importTips10: ' information, please complete, then import!',
+	importTips11: 'File read successfully!',
+	importTips12: 'Please check if the form data is correct!',
+	importInfo1: 'Total Student Number:',
+	importInfo2: 'Repeated Account/Student ID:',
+	importInfo3: 'Repeated Seat Number:',
+	importInfo4: 'No corresponding classroom:',
+	importInfo5: 'The account already exists in the system:',
+	importInfo6: 'Can be imported:',
+	passwordTips: 'Items with no password found will default to the same password as the account/student ID',
+	submitList: 'Create Account',
+	lackAttr: 'Incomplete Excel Column:',
+	noSetNo: 'No Seat Number:',
+	gradeErr: 'Grade Error:',
+	attrWarning: 'Warning: Excel Column is incomplete!',
+	setNoWarning: 'Warning: Seat number is repeated in Excel!',
+	idWarning: 'Warning: Account/student ID is repeated in Excel!',
+	idFormatWarning: 'Error:Student account format is a 4-12 digit number',
+	gradeWarning: 'Warning: Error in grade',
+	setNoErr: "Error: Seat number has been repeated within the school",
+	downloadText: '(Download List Sample)',
+	idRepErr: 'Account already exists, will overwrite the original account',
+	stuYearErr: "Student's academic year data is incorrect",
+	classYearErr: "Class's grade level is incorrect",
+	noFormatErr: 'Incorrect seat number format',
+	classFormatErr: 'Incorrect class format',
+	classNameErr: 'Class name abnormal',
+	importOk: 'Import successfully',
 
-  //StudentList.vue
-  filterLabel:'Filter by:',
-  noSchool:'Not attributed to a school yet',
-  isBottom:'This is the bottom'
+	// Authorization.vue
+	authTitle: 'Service Authorization Management',
+	authTitle1: 'AClass One Learning Companion Service Authorization',
+	authDiscraption: 'Grant access to the Learning Companion App to students with TEAM Model IDs that are authorized to use the service.',
+	authCount: 'Total authorization number of school',
+	alreadyUse: 'Number of authorizations used today',
+	mayUse: 'Number of authorizations available',
+	authNum: 'Authorized use status of each school system',
+
+	//StudentList.vue
+	filterLabel: 'Filter by:',
+	noSchool: 'Not attributed to a school yet',
+	isBottom: 'This is the bottom'
 }

+ 16 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/syllabus.js

@@ -1,4 +1,20 @@
 export default{
+	shareSyllabus:'分享個人課綱',
+	chooseShareChapter:'選擇分享的章節',
+	allShare:'整冊分享',
+	chooseTeacher:'選擇分享的教師',
+	saveSyllabus:'收藏分享課綱',
+	chooseSaveSyllabus:'選擇要收藏的章節',
+	allSave:'整冊收藏',
+	chooseSavePos:'選擇收藏位置',
+	pos1:'已有冊別',
+	pos2:'新建冊別',
+	chooseVolume:'選擇一個冊別',
+	newVolume:'輸入新冊別名稱',
+	confirmSave:'確認收藏',
+	save:'收藏',
+	ignore:'忽略',
+	delTip1:'冊別已被分享者',
 	download:'Download',
 	orderUpdateTip:'Book order has been updated',
 	noSaveShare:'This topic has not been saved yet. Please save it before operation!',

+ 2 - 2
TEAMModelOS/ClientApp/src/locale/lang/en-US/teachContent.js

@@ -64,6 +64,6 @@ export default {
   common:'General',
   renameTitle:'Rename',
   fileName:'File Name:',
-  sltPeriod:'Please select at least one school system'
-  
+  sltPeriod:'Please select at least one school system',
+  nameRept:'文件名称重复'
 }

+ 1 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/researchCenter.js

@@ -4,5 +4,6 @@ export default{
         order: "次",
         part: "分",
         scienceScore: "科技互动指数",
+        TScore: "教学应用",
     }
 }

+ 135 - 134
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/stuAccount.js

@@ -1,140 +1,141 @@
 export default {
-  // table title
-  seatNo: '座号',
-  account: '账号/学号',
-  stuName: '姓名',
-  classroomCode: '班级',
-  classroomName: '班级名称',
-  period: '学段',
-  grade: '年级',
-  authStatus: '授权状态',
-  password: '密码',
-  abnormalStatus: '异常状态',
+	qrcode: '二维码贴纸',
+	// table title
+	seatNo: '座号',
+	account: '账号/学号',
+	stuName: '姓名',
+	classroomCode: '班级',
+	classroomName: '班级名称',
+	period: '学段',
+	grade: '年级',
+	authStatus: '授权状态',
+	password: '密码',
+	abnormalStatus: '异常状态',
 
-  // Index.vue
-  menuAuth: '授权管理',
-  importStu: '导入名单',
-  addStu: '新增学生',
-  editInfo: '编辑资讯',
-  delStu: '删除学生',
-  searchHolder: '输入关键字或账号资讯搜索',
-  periodHolder: '选择学段',
-  gradeHolder: '选择年级',
-  classroomHolder: '选择班级',
-  tips1: '请选择需要修改的学生!',
-  tips2Title: '删除学生',
-  tips2Content1: '确定删除',
-  tips2Content2: '账号信息!',
-  tips2Content3: '确认批量删除',
-  tips2Content4: '个学生',
-  tips3: '请选择需要删除的学生!',
-  sltPdFirst: '请先选择学段',
-  sltGdFirst: '请先选择年级',
-  noClass: '此年级暂无班级',
-  noRelClass: '未关联班级',
-  resetPw: '重置密码',
-  semYear: '学年度:',
-  delOk: '删除成功',
-  delErr: '删除失败',
-  isBottom: '已经到底了',
-  edit: '修改',
-  adminClass: '行政班',
-  teachClass: '教学班',
-  stuMgt: '学生管理',
-  filterNoClass: '筛选未关联班级学生',
-  updClass:'修改班级',
-  sltStuLabel:'选取学生:',
-  classLabel:'班级:',
+	// Index.vue
+	menuAuth: '授权管理',
+	importStu: '导入名单',
+	addStu: '新增学生',
+	editInfo: '编辑资讯',
+	delStu: '删除学生',
+	searchHolder: '输入关键字或账号资讯搜索',
+	periodHolder: '选择学段',
+	gradeHolder: '选择年级',
+	classroomHolder: '选择班级',
+	tips1: '请选择需要修改的学生!',
+	tips2Title: '删除学生',
+	tips2Content1: '确定删除',
+	tips2Content2: '账号信息!',
+	tips2Content3: '确认批量删除',
+	tips2Content4: '个学生',
+	tips3: '请选择需要删除的学生!',
+	sltPdFirst: '请先选择学段',
+	sltGdFirst: '请先选择年级',
+	noClass: '此年级暂无班级',
+	noRelClass: '未关联班级',
+	resetPw: '重置密码',
+	semYear: '学年度:',
+	delOk: '删除成功',
+	delErr: '删除失败',
+	isBottom: '已经到底了',
+	edit: '修改',
+	adminClass: '行政班',
+	teachClass: '教学班',
+	stuMgt: '学生管理',
+	filterNoClass: '筛选未关联班级学生',
+	updClass: '修改班级',
+	sltStuLabel: '选取学生:',
+	classLabel: '班级:',
 
-  // AddStudent.vue
-  accountInfo: '账号资讯',
-  accountHolder: '请输入账号信息',
-  passwordInfo: '密码',
-  passwordHolder: '请设置账号密码',
-  isSame: '与账号相同',
-  stuName: '学生姓名',
-  stuNameHolder: '请输入学生名称',
-  stuSeatNo: '座位号',
-  stuSeatNoHolder: '请设置座位号',
-  classroomInfo: '班级',
-  classroomInfoHolder: '请选择班级',
-  newClassroom: '建立新班级',
-  periodInfo: '学段',
-  gradeInfo: '年级',
-  submitAccount: '建立账号',
-  submitActive: '保存',
-  chooseInfo: '选取项目',
-  chooseNum: '总计:',
-  numUnit: '条',
-  academicYear: '学级',
-  noMatch: '暂无匹配数据',
-  stuIdErr: '学生账号不能为空',
-  stuIdErr1: '学生账号格式为4-12位的数字',
-  stuIdErr2: '学生账号重复',
-  setNoErr1:'请设置学生班级',
-  setNoErr2:'座号在班级中重复',
-  sltStuTips:'请先选择学生',
-  addOk:'添加成功',
-  updOk:'修改成功',
-  addErr:'添加失败',
-  updErr:'修改失败',
-  sltClassTips:'请设置班级',
-  classErr:'请设置学生所在班级',
-  pwErr:'密码不能为空',
-  nameErr:'学生姓名不能为空',
-  repeatErr:'账号或座号重复了',
+	// AddStudent.vue
+	accountInfo: '账号资讯',
+	accountHolder: '请输入账号信息',
+	passwordInfo: '密码',
+	passwordHolder: '请设置账号密码',
+	isSame: '与账号相同',
+	stuName: '学生姓名',
+	stuNameHolder: '请输入学生名称',
+	stuSeatNo: '座位号',
+	stuSeatNoHolder: '请设置座位号',
+	classroomInfo: '班级',
+	classroomInfoHolder: '请选择班级',
+	newClassroom: '建立新班级',
+	periodInfo: '学段',
+	gradeInfo: '年级',
+	submitAccount: '建立账号',
+	submitActive: '保存',
+	chooseInfo: '选取项目',
+	chooseNum: '总计:',
+	numUnit: '条',
+	academicYear: '学级',
+	noMatch: '暂无匹配数据',
+	stuIdErr: '学生账号不能为空',
+	stuIdErr1: '学生账号格式为4-12位的数字',
+	stuIdErr2: '学生账号重复',
+	setNoErr1: '请设置学生班级',
+	setNoErr2: '座号在班级中重复',
+	sltStuTips: '请先选择学生',
+	addOk: '添加成功',
+	updOk: '修改成功',
+	addErr: '添加失败',
+	updErr: '修改失败',
+	sltClassTips: '请设置班级',
+	classErr: '请设置学生所在班级',
+	pwErr: '密码不能为空',
+	nameErr: '学生姓名不能为空',
+	repeatErr: '账号或座号重复了',
 
-  // ImportStudent.vue
-  importTitle: '导入学生名单',
-  importTips1: '拖拽欲导入的学生账号和表格档案至此',
-  importTips2: '或',
-  importTips3: '点击文件图示打开文件浏览上传',
-  importTips4: '打开的文件已删除!',
-  importTips5: '文件类型错误',
-  importTips6: '文件:',
-  importTips7: '不是EXCEL文件,请选择后缀为.xlsx或者.xls的EXCEL文件。',
-  importTips8: '文件读取出错',
-  importTips9: '缺少',
-  importTips10: '信息,请完善,再导入!',
-  importTips11: '文件读取成功!',
-  importTips12: '请检查表格数据是否正确!',
-  importInfo1: '总名单数:',
-  importInfo2: '账号重复:',
-  importInfo3: '座号重复:',
-  importInfo4: '没有对应教室:',
-  importInfo5: '系统已存在账号:',
-  importInfo6: '可导入:',
-  passwordTips: '未导入密码的学生将默认密码与账号相同',
-  submitList: '建立账号',
-  lackAttr: 'Excel栏位有缺:',
-  noSetNo: '沒有座号:',
-  gradeErr: '年级错误:',
-  attrWarning: '警告:Excel 內栏位不完整!',
-  setNoWarning: '警告:Excel 內的座位号重覆!',
-  idWarning: '警告:Excel 內账号重复!',
-  idFormatWarning: '错误:学生账号格式为4-12数字',
-  gradeWarning: '警告:年级错误',
-  setNoErr: "错误:座位号已在校內重复",
-  downloadText: '(下载名单模板)',
-  idRepErr: '账号已存在,将覆盖原有账号',
-  stuYearErr: '学生学级数据错误',
-  classYearErr: '班级年级错误',
-  noFormatErr: '座号格式错误',
-  classFormatErr: '班级格式错误',
-  classNameErr: '班级名称异常',
-  importOk: '导入成功',
-  
-  // Authorization.vue
-  authTitle: '服务授权管理',
-  authTitle1: 'AClassOne智慧学伴服务授权',
-  authDiscraption: '赋予持有该服务授权的学生TEAM MODEL ID使用智慧学伴App权限。',
-  authCount: '学校总授权数',
-  alreadyUse: '今日已取用授权数',
-  mayUse: '可使用授权数',
-  authNum: '各学段授权使用状态',
+	// ImportStudent.vue
+	importTitle: '导入学生名单',
+	importTips1: '拖拽欲导入的学生账号和表格档案至此',
+	importTips2: '或',
+	importTips3: '点击文件图示打开文件浏览上传',
+	importTips4: '打开的文件已删除!',
+	importTips5: '文件类型错误',
+	importTips6: '文件:',
+	importTips7: '不是EXCEL文件,请选择后缀为.xlsx或者.xls的EXCEL文件。',
+	importTips8: '文件读取出错',
+	importTips9: '缺少',
+	importTips10: '信息,请完善,再导入!',
+	importTips11: '文件读取成功!',
+	importTips12: '请检查表格数据是否正确!',
+	importInfo1: '总名单数:',
+	importInfo2: '账号重复:',
+	importInfo3: '座号重复:',
+	importInfo4: '没有对应教室:',
+	importInfo5: '系统已存在账号:',
+	importInfo6: '可导入:',
+	passwordTips: '未导入密码的学生将默认密码与账号相同',
+	submitList: '建立账号',
+	lackAttr: 'Excel栏位有缺:',
+	noSetNo: '沒有座号:',
+	gradeErr: '年级错误:',
+	attrWarning: '警告:Excel 內栏位不完整!',
+	setNoWarning: '警告:Excel 內的座位号重覆!',
+	idWarning: '警告:Excel 內账号重复!',
+	idFormatWarning: '错误:学生账号格式为4-12数字',
+	gradeWarning: '警告:年级错误',
+	setNoErr: "错误:座位号已在校內重复",
+	downloadText: '(下载名单模板)',
+	idRepErr: '账号已存在,将覆盖原有账号',
+	stuYearErr: '学生学级数据错误',
+	classYearErr: '班级年级错误',
+	noFormatErr: '座号格式错误',
+	classFormatErr: '班级格式错误',
+	classNameErr: '班级名称异常',
+	importOk: '导入成功',
 
-  //StudentList.vue
-  filterLabel: '筛选条件:',
-  noSchool: '暂未归属学校',
-  isBottom: '已经到底了'
+	// Authorization.vue
+	authTitle: '服务授权管理',
+	authTitle1: 'AClassOne智慧学伴服务授权',
+	authDiscraption: '赋予持有该服务授权的学生TEAM MODEL ID使用智慧学伴App权限。',
+	authCount: '学校总授权数',
+	alreadyUse: '今日已取用授权数',
+	mayUse: '可使用授权数',
+	authNum: '各学段授权使用状态',
+
+	//StudentList.vue
+	filterLabel: '筛选条件:',
+	noSchool: '暂未归属学校',
+	isBottom: '已经到底了'
 }

+ 16 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/syllabus.js

@@ -1,4 +1,20 @@
 export default{
+	shareSyllabus:'分享个人课纲',
+	chooseShareChapter:'选择分享的章节',
+	allShare:'整册分享',
+	chooseTeacher:'选择分享的教师',
+	saveSyllabus:'收藏分享课纲',
+	chooseSaveSyllabus:'选择要收藏的章节',
+	allSave:'整册收藏',
+	chooseSavePos:'选择收藏位置',
+	pos1:'已有册别',
+	pos2:'新建册别',
+	chooseVolume:'选择一个册别',
+	newVolume:'输入新册别名称',
+	confirmSave:'确认收藏',
+	save:'收藏',
+	ignore:'忽略',
+	delTip1:'册别已被分享者',
 	download:'下载',
 	orderUpdateTip:'册别顺序已更新',
 	noSaveShare:'该章节暂未保存,请先保存再进行操作!',

+ 2 - 2
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/teachContent.js

@@ -64,6 +64,6 @@ export default {
   common:'通用(未关联学段资源)',
   renameTitle:'重命名',
   fileName:'文件名:',
-  sltPeriod:'请至少选择一个学段'
-
+  sltPeriod:'请至少选择一个学段',
+  nameRept:'文件名称重复'
 }

+ 2 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/cusMgt.js

@@ -174,6 +174,8 @@ export default {
     setOk:'設置成功',
     setErr:'設置失敗',
     uploadErr:'頭像上傳失敗',
+    deleteGroup:'刪除分組',
+    delGroupContent:'確認刪除',
     setAvatarLabel:'設置頭像',
     classStuErr:'獲取班級名單失敗',
 

+ 1 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/researchCenter.js

@@ -4,5 +4,6 @@ export default{
         order: "次",
         part: "分",
         scienceScore: "科技互動指數",
+        TScore: "教學應用",
     }
 }

+ 136 - 135
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/stuAccount.js

@@ -1,141 +1,142 @@
 export default {
-  // table title
-  seatNo: '座號',
-  account: '帳號/學號',
-  stuName: '姓名',
-  classroomCode: '班級',
-  classroomName: '教室名稱',
-  period: '學制',
-  grade: '年級',
-  authStatus: '授權狀態',
-  password: '密碼',
-  abnormalStatus: '異常狀態',
+	qrcode: '二維碼貼紙',
+	// table title
+	seatNo: '座號',
+	account: '帳號/學號',
+	stuName: '姓名',
+	classroomCode: '班級',
+	classroomName: '教室名稱',
+	period: '學制',
+	grade: '年級',
+	authStatus: '授權狀態',
+	password: '密碼',
+	abnormalStatus: '異常狀態',
 
-  //Index.vue
-  menuAuth: '授權管理',
-  importStu: '匯入名單',
-  addStu: '新增學生',
-  editInfo: '編輯資訊',
-  delStu: '刪除學生',
-  searchHolder: '輸入關鍵字或帳號資訊搜尋',
-  periodHolder: '選擇學制',
-  gradeHolder: '選擇年級',
-  classroomHolder: '選擇班級',
-  tips1: '請選擇需要修改的學生!',
-  tips2Title: '刪除學生',
-  tips2Content1: '確定刪除',
-  tips2Content2: '帳號資訊!',
-  tips2Content3: '確認批量刪除',
-  tips2Content4: '個學生',
-  tips3: '請選擇需要刪除的學生!',
-  sltPdFirst: '請先選擇學制',
-  sltGdFirst: '請先選擇學制',
-  noClass: '此年級暫無教室',
-  noRelClass: '未關聯班級',
-  resetPw: '重置密碼',
-  semYear: '學年度:',
-  delOk: '刪除成功',
-  delErr: '刪除失敗',
-  isBottom: '已經到底了',
-  edit:'修改',
-  adminClass:'編制班',
-  teachClass:'選課班',
-  stuMgt:'學生管理',
-  filterNoClass:'篩選未關聯班級學生',
-  updClass:'修改班級',
-  sltStuLabel:'選取學生:',
-  classLabel:'班級:',
+	//Index.vue
+	menuAuth: '授權管理',
+	importStu: '匯入名單',
+	addStu: '新增學生',
+	editInfo: '編輯資訊',
+	delStu: '刪除學生',
+	searchHolder: '輸入關鍵字或帳號資訊搜尋',
+	periodHolder: '選擇學制',
+	gradeHolder: '選擇年級',
+	classroomHolder: '選擇班級',
+	tips1: '請選擇需要修改的學生!',
+	tips2Title: '刪除學生',
+	tips2Content1: '確定刪除',
+	tips2Content2: '帳號資訊!',
+	tips2Content3: '確認批量刪除',
+	tips2Content4: '個學生',
+	tips3: '請選擇需要刪除的學生!',
+	sltPdFirst: '請先選擇學制',
+	sltGdFirst: '請先選擇學制',
+	noClass: '此年級暫無教室',
+	noRelClass: '未關聯班級',
+	resetPw: '重置密碼',
+	semYear: '學年度:',
+	delOk: '刪除成功',
+	delErr: '刪除失敗',
+	isBottom: '已經到底了',
+	edit: '修改',
+	adminClass: '編制班',
+	teachClass: '選課班',
+	stuMgt: '學生管理',
+	filterNoClass: '篩選未關聯班級學生',
+	updClass: '修改班級',
+	sltStuLabel: '選取學生:',
+	classLabel: '班級:',
 
-  //AddStudent.vue
-  accountInfo: '帳號資訊',
-  accountHolder: '請輸入帳號資訊',
-  passwordInfo: '密碼',
-  passwordHolder: '請設定帳號密碼',
-  isSame: '與帳號相同',
-  stuName: '學生姓名',
-  stuNameHolder: '請輸入學生名稱',
-  stuSeatNo: '座位號',
-  stuSeatNoHolder: '請設定座位號',
-  classroomInfo: '班級',
-  classroomInfoHolder: '請選擇班級',
-  newClassroom: '建立新班級',
-  periodInfo: '學制',
-  gradeInfo: '年級',
-  submitAccount: '建立帳號',
-  submitActive: '儲存',
-  chooseInfo: '選取項目',
-  chooseNum: '總計:',
-  numUnit: '條',
-  academicYear: '學級',
-  noMatch:'暫無匹配數據',
-  stuIdErr:'學生帳號不能為空',
-  stuIdErr1: '學生帳號格式為4-12位的數字',
-  stuIdErr2: '學生帳號重複',
-  setNoErr1:'請設置學生班級',
-  setNoErr2:'座號在班級中重複',
-  sltStuTips:'請先選擇學生',
-  addOk:'添加成功',
-  updOk:'修改成功',
-  addErr:'添加失敗',
-  updErr:'修改失敗',
-  sltClassTips:'請設置班級',
-  setNoErr:'學生座位號不能為空',
-  classErr:'請設置學生所在班級',
-  pwErr:'密碼不能為空',
-  nameErr:'學生姓名不能為空',
-  repeatErr:'帳號或座號重複了',
+	//AddStudent.vue
+	accountInfo: '帳號資訊',
+	accountHolder: '請輸入帳號資訊',
+	passwordInfo: '密碼',
+	passwordHolder: '請設定帳號密碼',
+	isSame: '與帳號相同',
+	stuName: '學生姓名',
+	stuNameHolder: '請輸入學生名稱',
+	stuSeatNo: '座位號',
+	stuSeatNoHolder: '請設定座位號',
+	classroomInfo: '班級',
+	classroomInfoHolder: '請選擇班級',
+	newClassroom: '建立新班級',
+	periodInfo: '學制',
+	gradeInfo: '年級',
+	submitAccount: '建立帳號',
+	submitActive: '儲存',
+	chooseInfo: '選取項目',
+	chooseNum: '總計:',
+	numUnit: '條',
+	academicYear: '學級',
+	noMatch: '暫無匹配數據',
+	stuIdErr: '學生帳號不能為空',
+	stuIdErr1: '學生帳號格式為4-12位的數字',
+	stuIdErr2: '學生帳號重複',
+	setNoErr1: '請設置學生班級',
+	setNoErr2: '座號在班級中重複',
+	sltStuTips: '請先選擇學生',
+	addOk: '添加成功',
+	updOk: '修改成功',
+	addErr: '添加失敗',
+	updErr: '修改失敗',
+	sltClassTips: '請設置班級',
+	setNoErr: '學生座位號不能為空',
+	classErr: '請設置學生所在班級',
+	pwErr: '密碼不能為空',
+	nameErr: '學生姓名不能為空',
+	repeatErr: '帳號或座號重複了',
 
-  //ImportStudent.vue
-  importTitle: '匯入學生名單',
-  importTips1: '拖移想匯入的學生帳號和表格檔案至此',
-  importTips2: '或',
-  importTips3: '點按檔案圖示以瀏覽檔案上傳',
-  importTips4: '打開的檔案已刪除!',
-  importTips5: '檔案類型錯誤',
-  importTips6: '檔案:',
-  importTips7: '不是EXCEL檔案,請選擇附加檔名為.xlsx或者.xls的EXCEL檔案。',
-  importTips8: '檔案讀取出錯',
-  importTips9: '缺少',
-  importTips10: '資訊,請完善,再匯入!',
-  importTips11: '檔案讀取成功!',
-  importTips12: '請檢查表格數據是否正確!',
-  importInfo1: '總名單數:',
-  importInfo2: '帳號重複:',
-  importInfo3: '座號重複:',
-  importInfo4: '沒有對應教室:',
-  importInfo5: '系統已存在帳號:',
-  importInfo6: '可匯入:',
-  passwordTips: '未導入密碼的學生將預設密碼與帳號相同',
-  submitList: '建立帳號',
-  lackAttr:'Excel欄位有缺:',
-  noSetNo:'沒有座號:',
-  gradeErr:'年級錯誤:',
-  attrWarning:'警告:Excel 內欄位不完整! ',
-  setNoWarning:'警告:Excel 內的座號重覆! ',
-  idWarning:'警告:Excel 內帳號重複! ',
-  idFormatWarning:'錯誤:學生帳號格式為4-12數字',
-  gradeWarning:'警告:年級錯誤',
-  setNoErr:"錯誤:座位號已在校內重複",
-  downloadText:'(下載名單模板)',
-  idRepErr:'帳號已存在,將覆蓋原有帳號',
-  stuYearErr:'學生學級數據錯誤',
-  classYearErr:'班級年級錯誤',
-  noFormatErr: '座號格式錯誤',
-  classFormatErr: '班級格式錯誤',
-  classNameErr: '班級名稱異常',
-  importOk: '導入成功',
+	//ImportStudent.vue
+	importTitle: '匯入學生名單',
+	importTips1: '拖移想匯入的學生帳號和表格檔案至此',
+	importTips2: '或',
+	importTips3: '點按檔案圖示以瀏覽檔案上傳',
+	importTips4: '打開的檔案已刪除!',
+	importTips5: '檔案類型錯誤',
+	importTips6: '檔案:',
+	importTips7: '不是EXCEL檔案,請選擇附加檔名為.xlsx或者.xls的EXCEL檔案。',
+	importTips8: '檔案讀取出錯',
+	importTips9: '缺少',
+	importTips10: '資訊,請完善,再匯入!',
+	importTips11: '檔案讀取成功!',
+	importTips12: '請檢查表格數據是否正確!',
+	importInfo1: '總名單數:',
+	importInfo2: '帳號重複:',
+	importInfo3: '座號重複:',
+	importInfo4: '沒有對應教室:',
+	importInfo5: '系統已存在帳號:',
+	importInfo6: '可匯入:',
+	passwordTips: '未導入密碼的學生將預設密碼與帳號相同',
+	submitList: '建立帳號',
+	lackAttr: 'Excel欄位有缺:',
+	noSetNo: '沒有座號:',
+	gradeErr: '年級錯誤:',
+	attrWarning: '警告:Excel 內欄位不完整! ',
+	setNoWarning: '警告:Excel 內的座號重覆! ',
+	idWarning: '警告:Excel 內帳號重複! ',
+	idFormatWarning: '錯誤:學生帳號格式為4-12數字',
+	gradeWarning: '警告:年級錯誤',
+	setNoErr: "錯誤:座位號已在校內重複",
+	downloadText: '(下載名單模板)',
+	idRepErr: '帳號已存在,將覆蓋原有帳號',
+	stuYearErr: '學生學級數據錯誤',
+	classYearErr: '班級年級錯誤',
+	noFormatErr: '座號格式錯誤',
+	classFormatErr: '班級格式錯誤',
+	classNameErr: '班級名稱異常',
+	importOk: '導入成功',
 
-  //Authorization.vue
-  authTitle: '服務授權管理',
-  authTitle1: 'AClass ONE智慧學伴服務授權',
-  authDiscraption: '賦予持有該服務授權的學生帳號AClass ONE智慧學伴App許可權。',
-  authCount: '學校總授權數',
-  alreadyUse: '今日已取用授權數',
-  mayUse: '可使用授權數',
-  authNum: '各學制授權使用狀態',
-  
-  //StudentList.vue
-  filterLabel:'篩選條件:',
-  noSchool:'暫未歸屬學校',
-  isBottom:'已經到底了'
+	//Authorization.vue
+	authTitle: '服務授權管理',
+	authTitle1: 'AClass ONE智慧學伴服務授權',
+	authDiscraption: '賦予持有該服務授權的學生帳號AClass ONE智慧學伴App許可權。',
+	authCount: '學校總授權數',
+	alreadyUse: '今日已取用授權數',
+	mayUse: '可使用授權數',
+	authNum: '各學制授權使用狀態',
+
+	//StudentList.vue
+	filterLabel: '篩選條件:',
+	noSchool: '暫未歸屬學校',
+	isBottom: '已經到底了'
 }

+ 25 - 9
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/syllabus.js

@@ -1,13 +1,29 @@
 export default {
-	download:'下載',
-	orderUpdateTip:'冊別順序已更新',
-	noSaveShare:'該章節暫未保存,請先保存再進行操作!',
+	shareSyllabus: '分享個人課綱',
+	chooseShareChapter: '選擇分享的章節',
+	allShare: '整冊分享',
+	chooseTeacher: '選擇分享的教師',
+	saveSyllabus: '收藏分享課綱',
+	chooseSaveSyllabus: '選擇要收藏的章節',
+	allSave: '整冊收藏',
+	chooseSavePos: '選擇收藏位置',
+	pos1: '已有冊別',
+	pos2: '新建冊別',
+	chooseVolume: '選擇一個冊別',
+	newVolume: '輸入新冊別名稱',
+	confirmSave: '確認收藏',
+	save: '收藏',
+	ignore: '忽略',
+	delTip1: '冊別已被分享者',
+	download: '下載',
+	orderUpdateTip: '冊別順序已更新',
+	noSaveShare: '該章節暫未保存,請先保存再進行操作!',
 	noShareMyself: '無法分享給自己',
-	copyChapter:'復製該章節',
-	ignoreChapter:'忽略該章節',
+	copyChapter: '復製該章節',
+	ignoreChapter: '忽略該章節',
 	from: '來自',
 	share: '分享',
-	noPreview:'該類型檔案不支持預覽!',
+	noPreview: '該類型檔案不支持預覽!',
 	praviteSyllabus: '個人課綱',
 	fromCreate: '我建立的課綱',
 	fromShare: '他人分享的課綱',
@@ -67,7 +83,7 @@ export default {
 	doSuc: '操作成功',
 	saveFailTip: '保存失敗',
 	isExistVolume: '已存在相同冊別',
-	unSaveTip:'當前冊別修改內容未保存,確認忽略修改並繼續操作嗎?',
+	unSaveTip: '當前冊別修改內容未保存,確認忽略修改並繼續操作嗎?',
 	tree: {
 		hasResource: '有關聯資源',
 		hasCoEdit: '有共編許可權',
@@ -80,8 +96,8 @@ export default {
 		addTitle: '新增節點',
 		parent: '父節點',
 		nodeName: '節點名稱',
-		addChapterTitle:'新增章節',
-		chapterName:'章節名稱',
+		addChapterTitle: '新增章節',
+		chapterName: '章節名稱',
 		place1: '請輸入節點名稱…',
 		confirm: '確認',
 		removeTitle: '刪除節點',

+ 2 - 2
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/teachContent.js

@@ -64,6 +64,6 @@ export default {
   common:'通用(未關聯學段資源)',
   renameTitle:'重命名',
   fileName:'文件名:',
-  sltPeriod:'請至少選擇一個學段'
-
+  sltPeriod:'請至少選擇一個學段',
+  nameRept:'文件名稱重複'
 }

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1272 - 1252
TEAMModelOS/ClientApp/src/router/routes.js


+ 90 - 33
TEAMModelOS/ClientApp/src/utils/blobTool.js

@@ -1,9 +1,12 @@
-import { GLOBAL } from '@/static/Global.js';
-import JsFn from '@/utils/js-fn.js';
-import Tools from '@/utils/public.js';
-import API from '@/api/index.js';
-const blobPath = ['avatar', 'audio', 'doc', 'exam', 'image', 'item', 'notice', 'other', 'paper', 'syllabus', 'res', 'student', 'survey', 'temp', 'thum', 'video', 'vote', 'jyzx', 'train', 'yxpt', 'homework', 'policy']
-const { BlobServiceClient, BlobClient } = require("@azure/storage-blob")
+import { GLOBAL } from '@/static/Global.js'
+import JsFn from '@/utils/js-fn.js'
+import Tools from '@/utils/public.js'
+import API from '@/api/index.js'
+import store from '@/store'
+
+const BLOB_PATH = ['avatar', 'audio', 'doc', 'exam', 'image', 'item', 'notice', 'other', 'paper', 'syllabus', 'res', 'student', 'survey', 'temp', 'thum', 'video', 'vote', 'jyzx', 'train', 'yxpt', 'homework', 'policy']
+const { BlobServiceClient } = require("@azure/storage-blob")
+
 //获取文件后缀和类型
 function getExAndType(fileName) {
     let ex = fileName.substring(fileName.lastIndexOf('.') + 1)
@@ -19,20 +22,44 @@ function getExAndType(fileName) {
         ex, type
     }
 }
-/**
- * 授权信息可以内部处理,不用每次调用都需要处理好授权信息
- */
+
 export default class BlobTool {
+    /**
+     * BlobTool生产方法
+     * @param {string} scope 学校(school)/个人(private)
+     * @param {object} options 初始化所需参数 host、container、sas
+     */
+    static CreateBlobTool(scope, options) {
+        if (!scope) {
+            throw new Error("CreateBlobTool参数(scope)错误,创建BlobTool失败")
+        }
+        //优先使用传入参数初始化
+        if (options) {
+            let { host, container, sas } = options
+            if (host && container && sas) {
+                return new BlobTool(host, container, '?' + sas, scope)
+            } else {
+                throw new Error("CreateBlobTool参数(options)异常,创建BlobTool失败")
+            }
+        }
+        let sas = scope == 'school' ? store.state?.user?.schoolProfile?.blob_sas : store.state?.user?.userProfile?.blob_sas
+        let blobUrl = scope == 'school' ? JSON.parse(decodeURIComponent(localStorage.school_profile, "utf-8"))?.blob_uri : JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8"))?.blob_uri
+        let host = blobUrl?.substring(0, blobUrl?.lastIndexOf('/'))
+        let cont = blobUrl?.substring(blobUrl?.lastIndexOf('/') + 1)
+        return new BlobTool(host, cont, '?' + sas, scope)
+    }
+
     /**
      * 初始化Blob,需要先调用授权API
      * @param {string} blobUrl blob地址
      * @param {string} container 容器名称
-     * @param {string} sasString 授权 需要前面有 “ ? ”
+     * @param {string} sasString 授权 需要前面有 '?'
      * @param {string} scope 学校(school)/个人(private) 计算空间大小
      * */
     constructor(blobUrl, container, sasString, scope) {
         this.initBlob(blobUrl, container, sasString, scope)
     }
+
     /**
      * 初始化Blob,需要先调用授权API
      * @param {string} blobUrl blob地址
@@ -41,7 +68,6 @@ export default class BlobTool {
      * @param {string} scope 学校(school)/个人(private) 计算空间大小
      * */
     initBlob(blobUrl, container, sasString, scope) {
-        console.log(...arguments);
         if (blobUrl && container && sasString && scope) {
             //初始化containerClient
             this.blobService = new BlobServiceClient(blobUrl + sasString)
@@ -61,12 +87,13 @@ export default class BlobTool {
                     this.blobSpace = school_profile && school_profile.school_base ? school_profile.school_base.size : 0
                 }
             } else {
-                throw new Error("参数错误,初始化失败")
+                throw new Error("initBlob参数错误,初始化失败")
             }
         } else {
-            throw new Error("初始化参数不完整")
+            throw new Error("initBlob初始化参数不完整,初始化失败")
         }
     }
+
     /**
      * 获取容器信息 (授权失败,需要账号级别的授权)
      * @param {object} 
@@ -86,6 +113,7 @@ export default class BlobTool {
             )
         })
     }
+
     /**
      * 获取指定分块的md5值
      * @param {any} url 相对路径 eg: video/test.mp4
@@ -126,20 +154,28 @@ export default class BlobTool {
 
     /**
      * 上传文件方法,带回调上传进度
-     * @param {any} file 文件对象
-     * @param {any} path 文件夹路径 只需要文件夹名称 前后都不需要加‘/’
+     * @param {File} file 文件对象
+     * @param {Object} config 配置项 {path,root,checkExist,checkSize}
+     * {string} 必填 path 文件夹路径 只需要文件夹名称 前后都不需要加‘/’
+     * {string} 选填 root path验证的根目录 默认为'/' 
+     * {boolean} 选填 checkSize 上传时是否检查容器空间 默认为 true
+     * {boolean} 选填 checkExist 是否检查文件重复 默认为 false(直接覆盖) 如果为ture会重命名上传
+     * 
      * @param {any} option 官方可配置项
-     * @param {any} checkSize 上传时是否检查容器空间 默认需要检查大小
-     * @param {any} root path验证的根目录 默认为'/'
      * @returns {object} {url, name,size,createTime,extension,type}
      */
-    upload(file, path, option = {}, checkSize = true, root = '/') {
+    // upload(file, path, option = {}, checkSize = true, root = '/') { //原来参数格式
+    upload(file, config = {}, option = {}) {
+        let { path, root, checkSize, checkExist } = config
+        //验证和初始化参数
+        if (!path) throw new Error('上传失败:config.path必传')
+        root = root || '/'
+        checkSize = checkSize == undefined ? true : checkSize
+        checkExist = checkExist == undefined ? false : checkExist
+
         let checkPath = root === '/' ? path : path.replace(root, '')
-        console.log(root);
-        console.log(checkPath);
-        if (!blobPath.includes(checkPath.split('/')[0])) {
-            throw new Error('上传路径不合法,请检查上传路径:' + path)
-        }
+        if (!BLOB_PATH.includes(checkPath.split('/')[0])) throw new Error('上传路径不合法,请检查上传路径:' + path)
+
         return new Promise(async (r, j) => {
             //检查容器空间大小
             let isFull = false
@@ -148,13 +184,26 @@ export default class BlobTool {
                     isFull = await this.isContainerFull(this.scope)
                 } catch (e) {
                     j({ spaceError: '容器空间计算失败,无法上传文件' })
+                    return
                 }
                 if (isFull) {
                     j({ spaceError: 'Blob空间已满,无法上传' })
+                    return
                 }
             }
 
-            const blockBlobClient = this.containerClient.getBlockBlobClient(path + "/" + file.name)
+            //检查文件是否存在
+            let fileName = file.name
+            let isExist = false
+            if (checkExist) {
+                let index = 1
+                while (await this.exists(path + '/' + fileName)) {
+                    fileName = `${file.name.slice(0, file.name.lastIndexOf('.'))}(${index})${file.name.slice(file.name.lastIndexOf('.'))}`
+                    isExist = true
+                    index++
+                }
+            }
+            const blockBlobClient = this.containerClient.getBlockBlobClient(path + "/" + fileName)
             blockBlobClient.uploadBrowserData(file, option).then(
                 res => {
                     //设置blob MD5 (解决大文件分块上传没有MD5的问题)
@@ -165,7 +214,7 @@ export default class BlobTool {
                                 let option = {
                                     blobContentMD5: res
                                 }
-                                this.setFileProperties(path + "/" + file.name, option).then(
+                                this.setFileProperties(path + "/" + fileName, option).then(
                                     res => {
                                         console.log('MD5设置成功', res)
                                     },
@@ -181,16 +230,17 @@ export default class BlobTool {
                     }
                     let url = decodeURIComponent(res._response.request.url)
                     url = url.substring(0, url.lastIndexOf('?'))
-                    let info = getExAndType(file.name)
+                    let info = getExAndType(fileName)
                     r({
                         url: url,
                         md5: res.contentMD5,
-                        blob: '/' + path + "/" + file.name,
-                        name: file.name,
+                        blob: '/' + path + "/" + fileName,
+                        name: fileName,
                         size: file.size,
                         createTime: res.lastModified.getTime(),
                         extension: info.ex,
-                        type: info.type
+                        type: info.type,
+                        isExist: isExist
                     })
                 },
                 err => {
@@ -199,6 +249,7 @@ export default class BlobTool {
             )
         })
     }
+
     /**
      * 处理HTEX文件类型
      * @param {blobList} fileList 
@@ -232,6 +283,7 @@ export default class BlobTool {
         })
         return parseRes
     }
+
     /**
      * 列出目录结构
      * @param {string} delimiter  分割符 默认'/'
@@ -268,7 +320,7 @@ export default class BlobTool {
      * eg: option.prefix = 'res' 只查res文件夹下的blob
      * @returns {object} {blobList, continuationToken}
      */
-     listBlob(option, hendleHTEX = true) {
+    listBlob(option, hendleHTEX = true) {
         return new Promise(async (r, j) => {
             let blobList = []
             if (this.containerClient) {
@@ -303,6 +355,7 @@ export default class BlobTool {
             }
         })
     }
+
     /**
      * 分页列出(查询)
      * @param {Object} option ContainerListBlobsOptions
@@ -350,6 +403,7 @@ export default class BlobTool {
             }
         })
     }
+
     /**
      * 删除Blob
      * @param {string} filePath 文件url + 容器 之后的路径
@@ -394,6 +448,7 @@ export default class BlobTool {
             )
         })
     }
+
     /**
      * 批量删除Blob 循环操作
      * @param {string} files 
@@ -415,6 +470,7 @@ export default class BlobTool {
             )
         })
     }
+
     /**
      * 获取blob属性
      * @param {string} url //blob完整路径包含授权 eg:'doc/醍摩豆账号.xlsx'
@@ -423,6 +479,7 @@ export default class BlobTool {
         let blobClient = this.containerClient.getBlockBlobClient(url)
         return blobClient.getProperties()
     }
+
     /**
      * 设置文件header
      * @param {string} url //blob完整路径包含授权 eg:'doc/醍摩豆账号.xlsx'
@@ -521,6 +578,7 @@ export default class BlobTool {
 
         })
     }
+
     /**
      * 判断文件是否存在
      * @param {string} filePath 文件路径 正确 'res/基础操作范例_16x9.HTE ' 错误 '/res/基础操作范例_16x9.HTE'
@@ -586,7 +644,7 @@ export default class BlobTool {
                             }
                             res.catalog.appData = res.size - contentSize
                             res.catalog.total = res.size
-                            res.catalog.teachSpace = res.teach //查询学校空间的时候,返回此学校已分配给教室的空间;查询个人容器返回为零,不需要处理
+                            res.catalog.teachSpace = res.teach ? res.teach * 1024 * 1024 * 1024 : 0 //查询学校空间的时候,返回此学校已分配给教室的空间;查询个人容器返回为零,不需要处理
                             r(res.catalog)
                         } else {
                             j('API error')
@@ -602,5 +660,4 @@ export default class BlobTool {
         }
 
     }
-
-}
+}

+ 1 - 1
TEAMModelOS/ClientApp/src/utils/evTools.js

@@ -364,7 +364,7 @@ export default {
 					let file = new File([JSON.stringify(itemJsonFile)], exerciseItem.id + ".json");
 					try{
 						// 等待上传blob的返回结果
-						let blobFile = await containerClient.upload(file, 'item/' + exerciseItem.id)
+						let blobFile = await containerClient.upload(file, { path:'item/' + exerciseItem.id })
 						if (blobFile.blob) {
 							// 保存试题JSON文件到试卷文件夹需要
 							itemJsonFiles.push(file)

+ 3 - 3
TEAMModelOS/ClientApp/src/utils/public.js

@@ -637,7 +637,7 @@ export default {
 						PDF.addPage()
 					}
 				})
-				PDF.save('二维码贴纸(' + pdfName + ').pdf')
+				PDF.save(app.$t('stuAccount.qrcode') + '(' + pdfName + ').pdf')
 				resolve(200)
 			})
 		})
@@ -826,7 +826,7 @@ export default {
 		try {
 			let id = vm.curId || vm.$parent.curId
 			// 上传文件
-			let blobFile = await containerClient.upload(file, 'item/' + id)
+			let blobFile = await containerClient.upload(file, { path:'item/' + id })
 			// 获取blob链接以及视频封面截图
 			const fileSas = await this.getFileSas(blobFile.url)
 			// const fileBlobUrl = encodeURI(blobFile.url) + '?' + fileSas.sas
@@ -882,7 +882,7 @@ export default {
 		try {
 			let id = vm.curId || vm.$parent.curId
 			// 上传文件
-			let blobFile = await containerClient.upload(file, 'item/' + id)
+			let blobFile = await containerClient.upload(file, { path:'item/' + id })
 			console.log(blobFile)
 			// 获取blob链接以及视频封面截图
 			const fileSas = await this.getFileSas(blobFile.url)

+ 2 - 2
TEAMModelOS/ClientApp/src/view/ability/TestPaper.vue

@@ -281,7 +281,7 @@
 							let file = new File([JSON.stringify(item)], curId + ".json");
 							try {
 								// 等待上传blob的返回结果
-								let blobFile = await containerClient.upload(file, `yxpt/${this.curStandard}/train/` + qnBaseInfo.id);
+								let blobFile = await containerClient.upload(file, { path:`yxpt/${this.curStandard}/train/` + qnBaseInfo.id });
 								if (blobFile.blob) {
 									console.log('上传Blob成功', blobFile)
 									r(`/train/${qnBaseInfo.id}/${curId}.json`)
@@ -325,7 +325,7 @@
 						);
 						let file = new File([JSON.stringify(qnBaseInfo)], "index.json");
 						// 等待上传blob的返回结果
-						let blobFile = await containerClient.upload(file, `yxpt/${this.curStandard}/train/` + qnBaseInfo.id);
+						let blobFile = await containerClient.upload(file, { path:`yxpt/${this.curStandard}/train/` + qnBaseInfo.id });
 						if (blobFile.blob) {
 							delete qnBaseInfo.slides
 							resolve(blobFile.blob)

+ 2 - 26
TEAMModelOS/ClientApp/src/view/abilityMgmt/Index.vue

@@ -1423,7 +1423,7 @@
 					// 先把对应试题目录下的全部复制到校本BLOB 然后再更新添加学段科目等字段后的题目Json文件
 					toClient.copyFolder(path, path.slice(0, path.length - 1), fromClient).then(async res => {
 						try {
-							let blobFile = await toClient.upload(file, "item/" + pItem.id);
+							let blobFile = await toClient.upload(file, { path:"item/" + pItem.id });
 							if (blobFile.blob) {
 								this.saveExercise(pItem).then(result => {
 									console.log(result)
@@ -1599,8 +1599,7 @@
 					this.containerClient.copyFolder(path, path.slice(0, path.length - 1), privareBlobTool)
 						.then(async res => {
 							try {
-								let blobFile = await this.containerClient.upload(file, "paper/" + paper
-									.name);
+								let blobFile = await this.containerClient.upload(file, { path:"paper/" + paper.name });
 								if (blobFile.blob) {
 									this.savePaperToCosmos(paper, scoring, isUpdate).then(result => {
 										console.log(result)
@@ -2077,29 +2076,6 @@
 					return item.type !== 'item' && item.type !== 'paper' && item.type !== 'link'
 				}
 			},
-			hasVolumeAuth() {
-				return auth => {
-					return (!this.isSchool && !this.inShareView) || this.$access.can('area.*|Syllabus_Edit') || (
-						auth && auth.length && auth.map(i => i.tmdid).includes(this.curTeammodelId))
-				}
-			},
-			hasEditAuth() {
-				return nodeData => {
-					if (!nodeData.id) return false
-					let userId = this.curTeammodelId
-					// 判断是否为一级节点,如果是二级节点则需要拿对应的一级节点去做判断
-					let chapterId = nodeData.pid === this.curVolume.id ? nodeData.id : this.getChapterIdById(nodeData
-						.id)
-					let chapterNode = this.treeOrigin.find(i => i.id === chapterId)
-					return this.$access.can('area.*|Syllabus_Edit') || this.curVolume.auth.map(i => i.tmdid).includes(
-						userId) || (chapterNode.auth && chapterNode.auth.length &&
-						chapterNode.auth.map(i => i.tmdid).includes(userId))
-				}
-			},
-			// 是否可以操作课纲模块(个人课纲或者管理员或者有课纲权限)
-			hasSyllabusAuth() {
-				return !this.isSchool || this.$access.can('area.*|Syllabus_Edit')
-			},
 			inShareView() {
 				return !this.isSchool && this.activeTab === 'fromShare'
 			},

+ 17 - 9
TEAMModelOS/ClientApp/src/view/areaMgmt/AreaData.vue

@@ -147,6 +147,11 @@ export default {
     },
     data() {
         return {
+            onlineTime: 20,
+            offlineTime: 10,
+            videoTime: 5,
+            submitTime: 15,
+            totalTime: 50,
             teacherData: [],
             defImg: '',
             vuescroolOpt: {
@@ -215,7 +220,6 @@ export default {
             hourData: [
                 {
                     name: '线上研修',
-                    total: 20,
                     complete: 0,
                     going: 0,
                     uncomplete: 0,
@@ -225,7 +229,6 @@ export default {
                 },
                 {
                     name: '校本研修',
-                    total: 10,
                     complete: 0,
                     going: 0,
                     uncomplete: 0,
@@ -235,7 +238,6 @@ export default {
                 },
                 {
                     name: '认证材料',
-                    total: 15,
                     complete: 0,
                     going: 0,
                     uncomplete: 0,
@@ -245,7 +247,6 @@ export default {
                 },
                 {
                     name: '课堂实录',
-                    total: 5,
                     complete: 0,
                     going: 0,
                     uncomplete: 0,
@@ -335,6 +336,13 @@ export default {
             this.$api.ability.getAreaData(params).then(
                 res => {
                     if (!res.error) {
+                        //设置的学时
+                        this.onlineTime = res.setting.onlineTime || this.onlineTime
+                        this.offlineTime = res.setting.offlineTime || this.offlineTime
+                        this.submitTime = res.setting.submitTime || this.submitTime
+                        this.videoTime = res.setting.classTime || this.videoTime
+                        this.totalTime = res.setting.allTime || this.totalTime
+
                         //能力点维度统计
                         // this.dimensions = this.$GLOBAL.DIMENSIONS()
                         this.dimensions = res.setting.dimensions
@@ -382,23 +390,23 @@ export default {
                         let schoolCount = {}
                         res.teacherTrains.forEach(item => {
                             //线上研修
-                            item.onlineTime == 0 ? onlinePending++ : item.onlineTime >= 20 ? onlineFinish++ : onlineGoing++
+                            item.onlineTime == 0 ? onlinePending++ : item.onlineTime >= this.onlineTime ? onlineFinish++ : onlineGoing++
 
                             //学习时长
                             allMinite += item.currency.videoTime
 
                             //校本研修
-                            item.offlineTime == 0 ? offlinePending++ : item.offlineTime >= 10 ? offlineFinish++ : offlineGoing++
+                            item.offlineTime == 0 ? offlinePending++ : item.offlineTime >= this.offlineTime ? offlineFinish++ : offlineGoing++
 
                             //认证材料
-                            item.currency.submitTime == 0 ? submitPending++ : item.currency.submitTime >= 15 ? submitFinish++ : submitGoing++
+                            item.currency.submitTime == 0 ? submitPending++ : item.currency.submitTime >= this.submitTime ? submitFinish++ : submitGoing++
 
                             //课堂实录
-                            item.classTime == 0 ? classPending++ : item.classTime >= 5 ? classFinish++ : classGoing++
+                            item.classTime == 0 ? classPending++ : item.classTime >= this.videoTime ? classFinish++ : classGoing++
 
                             //按学校统计
                             if (!schoolCount[item.school]) schoolCount[item.school] = [0, 0, 0]
-                            item.totalTime == 0 ? schoolCount[item.school][0]++ : item.totalTime < 50 ? schoolCount[item.school][1]++ : schoolCount[item.school][2]++
+                            item.totalTime == 0 ? schoolCount[item.school][0]++ : item.totalTime < this.totalTime ? schoolCount[item.school][1]++ : schoolCount[item.school][2]++
                         })
                         console.log('学校统计', schoolCount)
 

+ 11 - 5
TEAMModelOS/ClientApp/src/view/areatrain/Create.vue

@@ -220,7 +220,7 @@
                     <div class="img-box" :style="{backgroundImage: `url(${trainInfo.img || defImg})`}"></div>
                     <div class="base-info-wrap">
                         <div class="infos">
-                            
+
                             <div class="info-item">
                                 <span class="info-label">
                                     <!-- {{$t('train.create.topic')}} -->
@@ -740,9 +740,11 @@ export default {
                         let file = new File([JSON.stringify(item)], curId + ".json");
                         try {
                             // 等待上传blob的返回结果
-                            // let blobFile = await containerClient.upload(file, `train/${qnBaseInfo.id}`);
-                            console.log('11', containerClient)
-                            let blobFile = await containerClient.upload(file, `${this.areaId}/${type}/${qnBaseInfo.id}`, {}, false, `${this.areaId}/`);
+                            let blobFile = await containerClient.upload(file, {
+                                path: `${this.areaId}/${type}/${qnBaseInfo.id}`,
+                                checkSize: false,
+                                root: `${this.areaId}/`
+                            });
                             if (blobFile.blob) {
                                 r(blobFile.blob)
                             } else {
@@ -780,7 +782,11 @@ export default {
                 let file = new File([JSON.stringify(info)], "index.json");
                 try {
                     // 等待上传blob的返回结果
-                    let blobFile = await containerClient.upload(file, `${this.areaId}/${type}/${qnBaseInfo.id}`, {}, false, `${this.areaId}/`);
+                    let blobFile = await containerClient.upload(file, {
+                        path: `${this.areaId}/${type}/${qnBaseInfo.id}`,
+                        checkSize: false,
+                        root: `${this.areaId}/`
+                    })
                     if (blobFile.blob) {
                         delete info.slides
                         r(blobFile.blob)

+ 5 - 0
TEAMModelOS/ClientApp/src/view/auth/Classroom.less

@@ -0,0 +1,5 @@
+.class-auth-container{
+    width: 100%;
+    height: 100%;
+    padding: 20px;
+}

+ 17 - 0
TEAMModelOS/ClientApp/src/view/auth/Classroom.vue

@@ -0,0 +1,17 @@
+<template>
+    <div class="class-auth-container">
+        教室列表
+    </div>
+</template>
+<script>
+export default {
+    data(){
+        return{
+
+        }
+    }
+}
+</script>
+<style lang="less" scoped>
+@import "./Classroom.less";
+</style>

+ 49 - 0
TEAMModelOS/ClientApp/src/view/auth/Index.less

@@ -0,0 +1,49 @@
+.auth-container{
+    width: 100%;
+    height: 100%;
+    display: flex;
+}
+.auth-main{
+    width: 100%;
+    height: 100%;
+}
+.auth-tab-wrap{
+    height: 45px;
+    width: 100%;
+    line-height: 45px;
+    padding-left: 20px;
+    box-shadow: 0px 2px 5px #e9e9e9;
+    background-color: white;
+}
+.space-box{
+    padding-left: 6px;
+    width: 100%;
+    height: 100%;
+}
+.auth-tab{
+    display: inline-block;
+    line-height: 26px;
+    cursor: pointer;
+    color: var(--second-text-color);
+    margin: 0px 30px 0px 0px;
+    user-select: none;
+    font-size: 14px;
+}
+.auth-tab-active{
+    border-bottom: 2px solid var(--tabs-bottom-color);
+    color: var(--tabs-text-color);
+    font-weight: 600;
+}
+.to-teacher-mgt{
+    line-height: initial;
+    cursor: pointer;
+    border-radius: 5px;
+    margin-top: 9px;
+    padding: 4px 10px;
+    background-color: #1cc0f3;
+    color: white;
+    font-weight: 700;
+    float: right;
+    margin-right: 20px;
+    user-select: none;
+}

+ 80 - 0
TEAMModelOS/ClientApp/src/view/auth/Index.vue

@@ -0,0 +1,80 @@
+<template>
+    <div class="auth-container">
+        <Split v-model="split1">
+            <div slot="left" class="auth-main">
+                <div class="auth-tab-wrap">
+                    <span @click="tabClick('product')" :class="['auth-tab',routerName == 'product' ? 'auth-tab-active':'']">
+                        服务授权管理
+                    </span>
+                    <span @click="tabClick('authroom')" :class="['auth-tab',routerName == 'authroom' ? 'auth-tab-active':'']">
+                        智慧教室授权管理
+                    </span>
+                </div>
+                <router-view></router-view>
+            </div>
+            <div slot="right" class="space-box">
+                <div class="auth-tab-wrap">
+                    <span>
+                        云端空间状态
+                    </span>
+                    <span class="to-teacher-mgt" @click="toTeacherMgt">
+                        <Icon type="md-share" style="margin-right:5px"/>
+                        分配教学空间
+                    </span>
+                </div>
+                <keep-alive include="SpaceInfo">
+                    <SpaceInfo></SpaceInfo>
+                </keep-alive>
+                <div class="auth-tab-wrap" style="margin-top:30px">
+                    <span>
+                        产品购买记录
+                    </span>
+                    <span class="to-teacher-mgt">
+                        <Icon type="md-archive" style="margin-right:5px"/>
+                        购买产品服务
+                    </span>
+                </div>
+                <EmptyData :top="80"></EmptyData>
+            </div>
+        </Split>
+    </div>
+</template>
+<script>
+import SpaceInfo from './SpaceInfo.vue'
+
+export default {
+    components: {
+        SpaceInfo
+    },
+    data() {
+        return {
+            split1: 0.75,
+            routerName: 'product',
+
+        }
+    },
+
+    methods: {
+        toTeacherMgt(){
+            this.$router.push({
+                name:'teachermgmt'
+            })
+        },
+        tabClick(routerName) {
+            if (routerName) {
+                this.routerName = routerName
+            }
+            this.$router.push({
+                name: this.routerName
+            })
+        },
+
+    },
+    mounted() {
+        this.routerName = this.$route.name
+    }
+}
+</script>
+<style lang="less" scoped>
+@import "./Index.less";
+</style>

+ 59 - 0
TEAMModelOS/ClientApp/src/view/auth/Product.less

@@ -0,0 +1,59 @@
+.product-container{
+    width: 100%;
+    height: 100%;
+}
+.product-item{
+    width: 100%;
+    padding: 30px 30px 30px 30px;
+    border: 1px solid var(--border-color);
+    margin-bottom: 20px;
+    border-radius: 4px;
+    background: white;
+    position: relative;
+}
+.product-name{
+    font-size: 20px;
+    font-weight: bolder;
+    display: flex;
+    align-items: center;
+}
+.product-status-tag{
+    font-size: 12px;
+    margin-left: 10px;
+    user-select: none;
+    background: #ed4014;
+    color: white;
+    padding: 1px 6px;
+    display: inline-block;
+}
+.product-status{
+    font-size: 14px;
+    color: var(--second-text-color);
+}
+.product-detail{
+    padding: 5px 0px;
+    font-weight: bolder;
+    color: #1cc0f3;
+    font-size: 14px;
+    margin-top: 5px;
+}
+.product-content{
+    font-size: 12px;
+    font-weight: 700;
+    color: #8d8d8d;
+}
+.toggle-status{
+    font-size: 30px;
+    position: absolute;
+    right: 20px;
+    top: 20px;
+    cursor: pointer;
+    transition: transform 0.1s;
+    &:hover{
+        color: #1cc0f3;
+    }
+}
+.toggle-status-active{
+    transform: rotate(180deg);
+    color: #1cc0f3;
+}

+ 71 - 0
TEAMModelOS/ClientApp/src/view/auth/Product.vue

@@ -0,0 +1,71 @@
+<template>
+    <div class="product-container">
+        <vuescroll>
+            <div v-for="(item,index) in productList" :key="index" class="product-item">
+                <p class="product-name">
+                    <span>
+                        {{item.name}}
+                    </span>
+                    <span class="product-status-tag">
+                        未购买
+                    </span>
+                </p>
+                <p class="product-status" style="margin-top:5px">
+                    服务启用 / 到期日: --
+                </p>
+                <p class="product-detail" v-show="activeTag.includes(item.name)">
+                    详细服务内容:
+                </p>
+                <p class="product-content" v-show="activeTag.includes(item.name)">
+                    待提供产品/模块说明内容
+                </p>
+                <Icon type="ios-arrow-down" @click="toggleStatus(item.name)" :class="['toggle-status', activeTag.includes(item.name) ? 'toggle-status-active' : '']" />
+            </div>
+        </vuescroll>
+
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {
+            productList: [
+                {
+                    name: '学校规模服务'
+                },
+                {
+                    name: '数据存储空间服务'
+                },
+                {
+                    name: '智慧学校管理模组'
+                },
+                {
+                    name: '学情分析模组'
+                },
+                {
+                    name: '教研中心模组'
+                }
+            ],
+            activeTag: []
+        }
+    },
+    methods: {
+        toggleStatus(name) {
+            let index = this.activeTag.indexOf(name)
+            if (index > -1) {
+                this.activeTag.splice(index,1)
+            } else {
+                this.activeTag.push(name)
+            }
+        }
+    }
+}
+</script>
+<style lang="less" scoped>
+@import "./Product.less";
+</style>
+<style lang="less">
+.product-container .__view {
+    padding: 30px 20px 50px 20px;
+}
+</style>

+ 192 - 0
TEAMModelOS/ClientApp/src/view/auth/SpaceInfo.vue

@@ -0,0 +1,192 @@
+<template>
+    <div id="space-info"></div>
+</template>
+<script>
+import BlobTool from '@/utils/blobTool.js'
+import { mapGetters } from 'vuex'
+import elementResizeDetectorMaker from "element-resize-detector"
+export default {
+    name: 'SpaceInfo',
+    computed: {
+        ...mapGetters({
+            SCHOOL_SPACE: 'SCHOOL_SPACE'
+        }),
+    },
+    data() {
+        return {
+            content: ['res', 'image', 'video', 'doc', 'audio', 'other'],
+            spaceInfo: {
+                total: '总空间',
+                // res: '教材',
+                // video: '视频',
+                // audio: '音频',
+                // image: '图片',
+                // doc: '文档',
+                // other:'其他内容',
+                exam: '评测',
+                vote: '投票',
+                survey: '问卷',
+                teachSpace: '分配给教师',
+                homework: '作业',
+                train: '研修',
+                over: '剩余'
+            },
+            formatData: [],
+            typeCountPie: undefined,
+            option: {
+                color:['#cccccc','#5470c6','#91cc75','#fac858','#ee6666','#73c0de','#3ba272','#fc8452','#9a60b4','#ea7ccc'],
+                tooltip: {
+                    trigger: 'item',
+                    // formatter: '{b}({c})',
+                    formatter: (params)=>{
+                        return `${params.name}:${this.$jsFn.formatBytes(params.value)}`
+                    },
+                    textStyle: {
+                        color: '#000'
+                    },
+                    backgroundColor: '#fff',
+                    extraCssText: 'box-shadow: 0px 0px 10px 0px rgba(19,83,88,0.2);'
+                },
+                title: [],
+                legend: {
+                    data: [],
+                    textStyle: {
+                        color: '#757575',
+                        padding: [5, 0, 5, 0]
+                    },
+                    icon: 'circle',
+                    bottom: 15
+                },
+                series: [
+                    {
+                        type: 'pie',
+                        center: ['50%', '35%'],
+                        radius: ['60%', '80%'],
+                        labelLine: {
+                            show: false
+                        },
+                        label: {
+                            show: false
+                        },
+                        data: []
+                    }
+                ]
+            }
+        }
+    },
+    mounted() {
+        if (!this.typeCountPie) this.typeCountPie = this.$echarts.init(document.getElementById('space-info'))
+        this.typeCountPie.setOption(this.option)
+        this.erd = elementResizeDetectorMaker()
+        this.erd.listenTo(document.getElementById("space-info"), () => {
+            this.$nextTick(() => {
+                //监听到事件后执行的业务逻辑
+                this.typeCountPie.resize()
+            })
+        })
+    },
+    methods: {
+        // 获取容器空间情况 
+        getSize() {
+            BlobTool.getContainerSize(this.$store.state.userInfo.schoolCode, 'school').then(
+                res => {
+                    console.log(res)
+                    this.sizeInfo = res
+                    let formatData = []
+                    let other = {
+                        name: '应用数据',
+                        value: 0
+                    }
+                    let content = {
+                        name: '内容模块',
+                        value: 0
+                    }
+                    if (res) {
+                        for (const key in res) {
+                            if (key != 'total' && key != 'appData') {
+                                if (this.spaceInfo[key]) {
+                                    formatData.push({
+                                        name: this.spaceInfo[key],
+                                        value: res[key]
+                                    })
+                                } else if (this.content.includes(key)) {
+                                    content.value += res[key]
+                                } else {
+                                    other.value += res[key]
+                                }
+                            }
+                        }
+                    }
+                    formatData.push(content)
+                    formatData.push(other)
+                    formatData.unshift({
+                        name: '剩余',
+                        value: this.SCHOOL_SPACE * 1024 * 1024 * 1024 - res.teachSpace - res.total
+                    })
+                    console.log(formatData)
+                    formatData = formatData.filter(item => !!item.value)
+                    this.option.legend.data = formatData.map(item => {
+                        return item.name
+                    })
+                    this.option.series[0].data = formatData
+                    this.option.title = []
+                    this.option.title.push({
+                        text: '{name|' + '总空间' + '}\n{val|' + this.SCHOOL_SPACE + 'GB' + '}',
+                        top: '25%',
+                        left: 'center',
+                        textStyle: {
+                            rich: {
+                                name: {
+                                    fontSize: 16,
+                                    fontWeight: 'normal',
+                                    color: '#757575',
+                                    padding: [10, 0],
+                                },
+                                val: {
+                                    fontSize: 35,
+                                    fontWeight: 'bold',
+                                    color: '#303030',
+                                },
+                            },
+                        },
+                    })
+                    this.$nextTick(() => {
+                        if (!this.typeCountPie) {
+                            this.typeCountPie = this.$echarts.init(document.getElementById('space-info'))
+                        }
+                        this.typeCountPie.setOption(this.option)
+                    })
+                },
+                err => {
+                    this.$Message.error(this.$t('teachContent.sizeErr'))
+                }
+            ).finally(() => {
+                this.sizeLoading = false
+            })
+        },
+    },
+    mounted() {
+        this.getSize()
+    },
+    watch: {
+        // SCHOOL_SPACE: {
+        //     handler(n, o) {
+        //         console.log('空间', n)
+        //     },
+        //     immediate: true,
+        //     deep: true
+        // }
+    }
+}
+</script>
+<style scoped lang="less">
+#space-info {
+    margin: auto;
+    margin-top: 20px;
+    width: 80%;
+    max-width: 300px;
+    height: 360px;
+}
+</style>
+<style>
+</style>

+ 0 - 71
TEAMModelOS/ClientApp/src/view/authorization/Index.less

@@ -1,71 +0,0 @@
-#authMgmt{    
-    width: 100%;
-    height: 100%;
-    color: #fff;
-    padding: 1%;
-    overflow-x: auto;
-    overflow-y: hidden;
-    .main{
-        white-space: nowrap;
-        display: -webkit-box;
-        display: -ms-flexbox;
-        display: flex;
-        height:95%;
-        .pane{
-            height: 100%;
-            border: 1px #333 solid;
-            padding:10px;
-            background-color: #13313e;
-            border:1px solid #333;
-            position: relative;
-            z-index:10;
-            box-shadow: 2px 0 2px 0px rgba(81, 90, 110, 0.5);
-            .title{
-                height:5%;
-            }
-            .head{
-                border-bottom: 1px solid rgb(148, 153, 138);
-                padding-bottom: 10px                
-            }
-            .conet{
-                overflow: auto;
-                height: 94%;
-                width: 100%;
-                .user{
-                    &:hover, &.active{
-                        background: -webkit-linear-gradient(right, rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: -o-linear-gradient(right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: -moz-linear-gradient(right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                        background: linear-gradient(to right,rgba(147, 166, 150, 0), rgba(147, 166, 150, 0.42));
-                    }
-                    padding: 15px 10px 10px 25px;
-                    background-color: rgba(17, 17, 17, 0.14);
-                    cursor: pointer;
-                    margin-bottom:5px;
-                    .box{
-                        height: 50px;
-                        .name{
-                            h3{
-                                font-size: 1.5em
-                            }
-                            span{
-                                font-size: 1em;color: #dcdee2;
-                            }
-                        }
-                        .nickName{
-                            span{
-                                font-size: 1em
-                            }
-                        }
-                        .play{
-                            text-align: right;
-                        }
-                    }
-                }
-            }
-        }
-        .pane-z-index-1{
-            z-index:1;
-        }
-    }
-}

+ 0 - 314
TEAMModelOS/ClientApp/src/view/authorization/Index.vue

@@ -1,314 +0,0 @@
-<style lang="less" scoped>
-  @import './Index.less';
-</style>
-
-<template>
-  <div id="authMgmt" class="backdrop-dark">
-    <h2 class="title">權限設定</h2>
-    <Row class="main">
-        <Col class="pane" :span="7">
-            <Row class="head">
-                <Col :span="10">
-                    <Input v-special-char v-model="filterName" suffix="ios-search" placeholder="ID / Name" />
-                </Col>
-                <Col :span="14">
-                    <Button @click="userPaneBtn('addUser')" style="float: right;" icon="md-add"></Button>
-                </Col>
-            </Row>
-            <div class="conet scrollstyle">
-                <div v-for="(user, index) in filterLists" :key="index" class="user" :class="{ 'active': user.id === userSelect }" @click="userPaneBtn('auth', user.id)">
-                    <Row class="box" type="flex" justify="center" align="middle">
-                        <Col class="name" :span="8">
-                            <h3>{{user.id}}</h3>
-                            <span>{{user.name}}</span>
-                        </Col>
-                        <Col class="nickName" :span="8"><span>{{user.nickName}}</span></Col>
-                        <Col class="play" :span="8"><Icon size="20" type="md-play" /></Col>
-                    </Row>
-                </div>
-            </div>
-        </Col>
-        <transition name="leftInOut">
-            <Col class="pane" style=" z-index:9;" v-if="userPane == 'addUser'" :span="4">
-                <Row style="border-bottom: 1px solid #94998a;padding-bottom: 10px;    min-height: 44px;">
-                    <Col :span="12">
-                        <h3>
-                            是否讓以下的老師加入:
-                            <!-- 老師加入後給予預設的權限 -->
-                        </h3>
-                    </Col>
-                    <Col :span="12">
-                        <a style="color:#fff;float: right;"  @click="closeBtn()"><Icon size="17" type="md-close" /></a>
-                    </Col>
-                </Row>
-                <Row class="scrollstyle"  style="margin-top: 10px;overflow: auto;height: 88%;">
-                    <Col>
-                        <div style="padding: 15px 10px 10px 15px;background-color: rgba(17, 17, 17, 0.14);cursor: pointer;margin-bottom: 5px;">
-                            <h3>JEFF-<small>JEFF#1234</small></h3>
-                             <RadioGroup>
-                                <Radio true-value="01" label="通過"></Radio>
-                                <Radio true-value="10" label="拒絕"></Radio>
-                            </RadioGroup>
-                        </div>
-                        <div style="padding: 15px 10px 10px 15px;background-color: rgba(17, 17, 17, 0.14);cursor: pointer;margin-bottom: 5px;">
-                            <h3>Mickey-<small>Mikey#1234</small></h3>
-                            <RadioGroup>
-                                <Radio true-value="01" label="通過"></Radio>
-                                <Radio true-value="10" label="拒絕"></Radio>
-                            </RadioGroup>
-                        </div>
-                    </Col>
-                </Row>
-                <Row >
-                    <Col style="text-align: right;">
-                        <Button>確定</Button>
-                    </Col>
-                </Row>
-            </Col>
-            </transition>
-        <transition name="leftInOut">
-            <Col class="pane" style=" z-index:8;" v-if="(userPane == 'addUser' && show)" :span="3">
-                addUser2
-            </Col>
-        </transition>
-        <transition name="leftInOut">
-            <Col class="pane"  style=" z-index:9;" v-if="userPane == 'auth'" :span="3">
-                <Row style="border-bottom: 1px solid #94998a;padding-bottom: 10px;    min-height: 44px;">
-                    <Col :span="12">
-                        <h3>
-                            {{userAuth.name}}
-                            <small>{{userAuth.id}}</small>
-                        </h3>
-                    </Col>
-                    <Col :span="12">
-                        <a style="color:#fff;float: right;"  @click="closeBtn()"><Icon size="17" type="md-close" /></a>
-                    </Col>
-                </Row>
-                <Row style="margin-top: 10px;">
-                    <Col :span="12" style="text-align: right;">
-                        <Input v-special-char size="small">
-                            <span slot="prepend">稱謂</span>
-                        </Input>
-                    </Col>
-                    <Col :span="12" style="text-align: right;">
-                        <Button size="small" icon="md-copy" @click="copyUserAuthFlag = true"></Button>
-                    </Col>
-                </Row>
-                <Row class="scrollstyle"  style="margin-top: 10px;overflow: auto;height: 84%;">
-                    <Col v-for="(item, authKey) in userAuth.authList" :key="authKey">
-                        <div style="padding: 15px 10px 10px 25px;background-color: rgba(17, 17, 17, 0.14);cursor: pointer;margin-bottom: 5px;">
-                            <Checkbox v-model="item.permissions"> {{item.path}}</Checkbox>
-                        </div>
-                        <transition name="leftInOut">
-                            <div v-if="item.permissions == 1">
-                                <ul style="margin-left: 15px;list-style-type: none;">
-                                    <li v-for="(value, name) in item.access">
-                                        <div style="padding: 15px 10px 10px 25px;background-color: rgba(17, 17, 17, 0.14);cursor: pointer;margin-bottom: 5px;">
-                                            {{ name }}
-                                            <Checkbox v-model="item.access[name]"></Checkbox>
-                                        </div>
-                                    </li>
-                                </ul>
-                            </div>
-                        </transition>
-                    </Col>
-                </Row>
-                <Row >
-                    <Col style="text-align: right;">
-                        <Button>確定</Button>
-                    </Col>
-                </Row>
-                <Spin size="large" fix v-if="authSpin">
-                    <Icon type="ios-loading" size=18 class="spin-icon-load"></Icon>
-                    <div>Loading</div>
-                </Spin>
-            </Col>
-        </transition>
-        <transition name="leftInOut">
-            <Col class="pane" style=" z-index:8;" v-if="copyUserAuthFlag" :span="3">
-                <Row style="border-bottom: 1px solid #94998a;padding-bottom: 10px;    min-height: 44px;">
-                    <Col :span="12">
-                        <h3>權限複製</h3>
-                    </Col>
-                    <Col :span="12">
-                        <a style="color:#fff;float: right;"  @click="copyUserAuthFlag = false"><Icon size="17" type="md-close" /></a>
-                    </Col>
-                </Row>
-                <Row style="margin-top: 10px;">
-                    <Col>
-                        <Input v-special-char v-model="filterNameBycopy" suffix="ios-search" placeholder="ID / Name" />
-                    </Col>
-                </Row>
-                <Row class="scrollstyle"  style="margin-top: 10px;overflow: auto;height: 88%;">
-                    <Col v-for="(item, key) in filterCopyName" :key="key">
-                        <div style="padding: 15px 10px 10px 15px;background-color: rgba(17, 17, 17, 0.14);cursor: pointer;margin-bottom: 5px;text-align:center;">
-                            {{item.name}}
-                        </div>
-                    </Col>
-                </Row>
-            </Col>
-        </transition>
-    </Row>
-  </div>
-</template>
-
-<script>
-export default {
-  data() {
-    return {
-        copyUserAuthFlag: false,
-        filterName: '',
-        filterNameBycopy: '',
-        userSelect: '', // 被點選的人
-        userPane: '', // 啟動的功能頁紀錄
-        authSpin: false, // 權限頁Spin
-        userList: [ // UserLIST
-            {
-                id: 'Osbert#1234',
-                name: '歐斯柏',
-                nickName: '老師',
-                authList: [
-                    {
-                        path: '/smartschooldashboard',
-                        component: 'smartschooldashboard',
-                        access: { // 小組件權限
-                            'fun1': true,
-                            'fun2': false
-                        },
-                        permissions: true // true: 有權訪問, false: 無權訪問
-                    },
-                    {
-                        path: '/smartclassdashboard',
-                        component: 'smartclassdashboard',
-                        access: { // 小組件權限
-                            'fun1': true,
-                            'fun2': false
-                        },
-                        permissions: true // true: 有權訪問, false: 無權訪問
-                    },
-                    {
-                        path: '/guidelines',
-                        component: 'guidelines',
-                        access: { // 小組件權限
-                            'fun1': true,
-                            'fun2': false
-                        },
-                        permissions: true // true: 有權訪問, false: 無權訪問
-                    }
-                ]
-            },
-            {
-                id: 'James#1234',
-                name: '詹姆士',
-                nickName: '老師',
-                authList: [
-                    {
-                        path: '/smartschooldashboard', // 頁面
-                        component: 'smartschooldashboard', // 組件名
-                        access: { // 小組件權限
-                            'fun1': false,
-                            'fun2': false
-                        },
-                        permissions: true // true: 有權訪問, false: 無權訪問
-                    },
-                    {
-                        path: '/smartclassdashboard',
-                        component: 'smartclassdashboard',
-                        access: { // 小組件權限
-                            'fun1': true,
-                            'fun2': false
-                        },
-                        permissions: true // true: 有權訪問, false: 無權訪問
-                    },
-                    {
-                        path: '/guidelines',
-                        component: 'guidelines',
-                        access: { // 小組件權限
-                            'fun1': false,
-                            'fun2': false
-                        },
-                        permissions: false // true: 有權訪問, false: 無權訪問
-                    }
-                ]
-            }
-        ],
-        userAuth: { // 使用者個人權限顯示
-            id: '',
-            name: '',
-            nickName: '',
-            authList: []
-        }
-
-    }
-  },
-  computed: {
-    filterLists: function() {
-    // 通通轉小寫比對。
-    let filterName = this.filterName.toLowerCase()
-
-    return (filterName.trim() !== '')
-        ? this.userList.filter(function(d) { return (d.name.toLowerCase().indexOf(filterName) > -1 || d.id.toLowerCase().indexOf(filterName) > -1) })
-        : this.userList
-    },
-    filterCopyName: function() {
-        // 通通轉小寫比對。
-        let filterName = this.filterNameBycopy.toLowerCase()
-
-        return (filterName.trim() !== '')
-        ? this.userList.filter(function(d) { return (d.name.toLowerCase().indexOf(filterName) > -1 || d.id.toLowerCase().indexOf(filterName) > -1) })
-        : this.userList
-    }
-  },
-  methods: {
-    async userPaneBtn(pane, id) {
-        this.userSelect = id
-        if (this.userPane != '' && this.userPane != pane) {
-           this.userPane = ''
-           await this.sleep(700)
-           this.userPane = pane
-        } else {
-            this.userPane = pane
-        }
-
-        switch (pane) {
-            case 'auth':
-                this.userAuthSeting(id)
-            break
-        }
-    },
-    closeBtn(pane) {
-        this.userPane = ''
-        this.userSelect = ''
-        this.copyUserAuthFlag = false
-    },
-    sleep(time) {
-        return new Promise((resolve) => setTimeout(resolve, time))
-    },
-    async userAuthSeting(id) {
-        // if(this.userSelect == id) return false;
-        this.authSpin = true
-        await this.sleep(2000)
-        let auth = this.userList.find(function(item) {
-            return item.id == id
-        })
-        this.userAuth.id = auth.id
-        this.userAuth.name = auth.name
-        this.userAuth.nickName = auth.nickName
-        this.userAuth.authList = auth.authList
-        this.authSpin = false
-    }
-  }
-}
-</script>
-<style scoped>
-.leftInOut-enter-active, .leftInOut-leave-active {
-    transition: all 0.7s;
-}
-.leftInOut-enter, .leftInOut-leave-to /* .list-leave-active below version 2.1.8 */ {
-    opacity: 0;
-    transform: translateX(-150px);
-}
-.spin-icon-load{
-    animation: ani-demo-spin 1s linear infinite;
-}
-</style>

+ 3 - 1
TEAMModelOS/ClientApp/src/view/classmgt/ClassStudent.vue

@@ -412,7 +412,9 @@ export default {
 
         },
         onBeforeUpload(file) {
-            this.blobTool.upload(file, 'avatar').then(
+            this.blobTool.upload(file, {
+                path:'avatar'
+            }).then(
                 res => {
                     this.avatarUrl = res.url
                 },

+ 2 - 2
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseEditExercise.vue

@@ -399,7 +399,7 @@
 						try {
 							console.log(exerciseItem)
 							// 等待上传blob的返回结果
-							let blobFile = await containerClient.upload(file, "item/" + guid);
+							let blobFile = await containerClient.upload(file, { path:"item/" + guid });
 							if (blobFile.blob) {
 								console.log(exerciseItem)
 								// 保存到COSMOS是不含base64图片编码的数据 避免数据量过大
@@ -466,7 +466,7 @@
 							);
 							try {
 								// 等待上传blob的返回结果
-								let blobFile = await containerClient.upload(file, "item/" + exerciseItem.id);
+								let blobFile = await containerClient.upload(file, { path:"item/" + exerciseItem.id });
 								if (blobFile.blob) {
 									// 保存到COSMOS是不含base64图片编码的数据 避免数据量过大
 									exerciseItem.blob = blobFile.blob;

+ 10 - 7
TEAMModelOS/ClientApp/src/view/evaluation/index/CreateExercises.vue

@@ -239,13 +239,15 @@
 				analysisEditor: null,
 				repairEditor: null,
 				curId: '',
-				isComplete: false
+				isComplete: false,
+				toolTimer:null
 			};
 		},
 		created() {
-			// 初始化区班校信息
-			// this.getSchoolInfo(0);
+			// 设置轮询来检测教学助手的开启状态
 			this.isToolAlive()
+			this.toolTimer = setInterval(this.isToolAlive,3000)
+			
 			let scope = this.$route.name === 'newSchoolExercise' ? 'school' : 'private'; // 编辑题目
 			if (scope) {
 				this.exerciseScope = scope === "private" ? 0 : 1;
@@ -253,7 +255,9 @@
 			}
 			// 先生成随机ID
 			this.curId = this.$tools.guid()
-
+		},
+		beforeDestroy(){
+			clearInterval(this.toolTimer)
 		},
 		methods: {
 			getSchoolInfo(periodIndex,storageInfo) {
@@ -472,7 +476,7 @@
 
 					try {
 						// 等待上传blob的返回结果
-						let blobFile = await containerClient.upload(file, "item/" + guid);
+						let blobFile = await containerClient.upload(file, { path:"item/" + guid });
 						if (blobFile.blob) {
 							// 保存到COSMOS是不含base64图片编码的数据 避免数据量过大
 							exerciseItem.blob = blobFile.blob;
@@ -537,8 +541,7 @@
 							);
 							try {
 								// 等待上传blob的返回结果
-								let blobFile = await containerClient.upload(file,
-									"item/" + exerciseItem.id, {}, true, false);
+								let blobFile = await containerClient.upload(file,{ path:"item/" + exerciseItem.id });
 								if (blobFile.blob) {
 									// 保存到COSMOS是不含base64图片编码的数据 避免数据量过大
 									exerciseItem.blob = blobFile.blob;

+ 5 - 9
TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue

@@ -574,9 +574,8 @@
 											// 等待上传blob的返回结果
 											let blobFile =
 												await containerClient
-												.upload(file, 'item/' +
-													composeItem.id,
-													undefined, false, false)
+												.upload(file, { path:'item/' +
+													composeItem.id,checkSize:false })
 											if (blobFile.blob) {
 												// 保存试题JSON文件到试卷文件夹需要
 												itemJsonFiles.push(composeItem)
@@ -632,9 +631,7 @@
 										// 等待上传blob的返回结果
 										let blobFile = await containerClient.upload(
 											file,
-											'item/' + exerciseItem.id, undefined,
-											false,
-											false)
+											{ path:'item/' + exerciseItem.id,checkSize:false })
 										if (blobFile.blob) {
 											// 保存试题JSON文件到试卷文件夹需要
 											// 保存到COSMOS是不含base64图片编码的数据 避免数据量过大
@@ -1133,8 +1130,7 @@
 											.createBlobItem(item)
 										let file = new File([JSON.stringify(itemJsonFile)],
 											item.id + ".json");
-										containerClient.upload(file, 'paper/' + paperItem
-											.name, undefined, false).then(res => {
+										containerClient.upload(file, { path:'paper/' + paperItem.name,checkSize:false}).then(res => {
 											r(200)
 										})
 									}
@@ -1148,7 +1144,7 @@
 						promiseArr.push(new Promise(async (r, j) => {
 							try {
 								blobFile = await containerClient.upload(paperFile,
-									'paper/' + paperItem.name, undefined, false)
+									{path:'paper/' + paperItem.name,checkSize:false})
 								console.log('上传到试卷目录下', blobFile)
 								r(blobFile)
 							} catch (e) {

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

@@ -795,7 +795,7 @@ export default {
                     let promiseArr = []
                     this.uploadList.map((item, index) => {
                         promiseArr.push(new Promise((r, j) => {
-                            blobTool.upload(item, path, {}, false).then(res => {
+                            blobTool.upload(item, {path, checkSize: false}).then(res => {
                                 res.hash = this.$tools.convertFileMD5ToString(res.md5)
                                 if(index === this.uploadIndex) {
                                     res.prime = true

+ 3 - 2
TEAMModelOS/ClientApp/src/view/knowledge-point/index/Index.vue

@@ -212,9 +212,9 @@
 				{{ isEditPoint ? $t('knowledge.editPoint') : $t('knowledge.addPoint')}}
 			</div>
 			<div class="modal-content">
-				<AddPoint :hideBlock="isShowPoints" :schoolParams="schoolParams" :blockData="parentBlock"
+				<AddPoint :isEditPoint="isEditPoint" :hideBlock="isShowPoints" :schoolParams="schoolParams" :blockData="parentBlock"
 					:orginPoint="originPointList" :pointData="currentPoint" :addType="pointOwn"
-					@addFinish="onFinishAddPoint">
+					@addFinish="onFinishAddPoint" v-if="isAddPoint">
 				</AddPoint>
 			</div>
 		</Modal>
@@ -973,6 +973,7 @@
 
 			// 编辑知识点事件
 			onEditPoint(data, index) {
+				console.log(data)
 				this.isAddPoint = true // 打开新增窗口
 				this.isEditPoint = true // 设置成编辑状态
 				this.currentPoint = data

+ 10 - 7
TEAMModelOS/ClientApp/src/view/knowledge-point/index/operation/AddPoint.vue

@@ -6,14 +6,14 @@
                 <Input v-special-char v-model="formTop.blockName" disabled />
             </FormItem>
             <FormItem :label="$t('knowledge.label')">
-                <Input v-special-char v-model="formTop.name" :placeholder="$t('knowledge.knowledgeP')" />
-                <vuescroll>
-                    <ul class="search-list" v-show="filterData.length > 0">
+                <Input v-special-char v-model="formTop.name" autofocus :placeholder="$t('knowledge.knowledgeP')" />
+                <!-- <vuescroll>
+                    <ul class="search-list" v-show="filterData.length > 0 && !isEditPoint">
                         <li v-for="(list,index) in filterData">
                             <span>{{list}}</span>
                         </li>
                     </ul>
-                </vuescroll>
+                </vuescroll> -->
             </FormItem>
             <FormItem>
                 <Button @click="handleAddPointSubmit()" :loading="isLoading">{{$t("knowledge.confirm")}}</Button>
@@ -25,7 +25,7 @@
 <script>
     import '@/utils/Math.uuid'
     export default {
-        props: ['blockData', 'pointData', 'hideBlock', 'addType', 'schoolParams', 'orginPoint'],
+        props: ['isEditPoint','blockData', 'pointData', 'hideBlock', 'addType', 'schoolParams', 'orginPoint'],
         data() {
             return {
                 blockDatas: null,
@@ -113,11 +113,14 @@
 
             pointData: {
                 handler(newValue, oldValue) {
+					console.log(newValue)
+					console.log(this.isEditPoint)
                     if (newValue) {
                         this.currentPoint = newValue
-                        this.formTop.name = newValue.name
+                        this.isEditPoint && (this.formTop.name = newValue)
                     }
-                }
+                },
+				immediate:true
             },
 
             schoolParams: {

+ 3 - 1
TEAMModelOS/ClientApp/src/view/learnactivity/ByQuMark.vue

@@ -270,7 +270,9 @@ export default {
             let cont = blobUrl.substring(blobUrl.lastIndexOf('/') + 1)
             let blobTool = new BlobTool(host, cont, '?' + sas, this.examInfo.scope)
             let path = `exam/${this.examInfo.id}/${this.subjectId}/${this.studentsData[this.stuIndex].id}`
-            blobTool.upload(markPng, path).then(
+            blobTool.upload(markPng, {
+                path
+            }).then(
                 res => {
                     if (!hasMarked) {
                         this.studentsData[this.stuIndex].mark[this.quIndex].push({

+ 14 - 13
TEAMModelOS/ClientApp/src/view/learnactivity/ByStuMark.vue

@@ -326,7 +326,7 @@
                 <p class="complete-next" @click="nextStu">{{$t('learnActivity.score.nextStu')}}</p>
             </div>
         </div>
-        <Modal v-model="markStatus" fullscreen :title="$t('learnActivity.score.mark')" class-name="mark-modal" @on-ok="saveMark(markData)" @on-cancel="closeModal">
+        <Modal v-model="markStatus" fullscreen :title="$t('learnActivity.score.mark')" class-name="mark-modal" @on-ok="saveMark(markData)" @on-cancel="closeModal" :loading="modalLoading">
             <BaseMark v-if="markStatus" defaultStatus="line" :bgImg="markBg" @onMarkChange="getMarkData"></BaseMark>
         </Modal>
         <!-- 用来单独渲染学生作答数据,提高tocanvas 的效率 -->
@@ -359,9 +359,9 @@ export default {
             default: '',
             required: true
         },
-        examInfo:{
-            type:Object,
-            default:()=>{
+        examInfo: {
+            type: Object,
+            default: () => {
                 return {}
             }
         },
@@ -396,6 +396,7 @@ export default {
     },
     data() {
         return {
+            modalLoading: true,
             originalStatus: false,
             markFlag: {},
             isUpd: false,
@@ -461,7 +462,7 @@ export default {
             let sas = this.examScope == 'school' ? this.$store.state.user.schoolProfile.blob_sas : this.$store.state.user.userProfile.blob_sas
             let blobUrl = this.examScope == 'school' ? JSON.parse(decodeURIComponent(localStorage.school_profile, "utf-8")).blob_uri : JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8")).blob_uri
             // let url = blobUrl + '/' + blob + '?' + sas
-            let url = `${blobUrl}/${blob}?${sas}&random=${this.$jsFn.getBtwRandom(10000,99999)}`
+            let url = `${blobUrl}/${blob}?${sas}&random=${this.$jsFn.getBtwRandom(10000, 99999)}`
             this.$set(this.markFlag, index, url)
         },
         setUpdStatus() {
@@ -508,7 +509,7 @@ export default {
             let cont = blobUrl.substring(blobUrl.lastIndexOf('/') + 1)
             let blobTool = new BlobTool(host, cont, '?' + sas, this.examScope)
             let path = `exam/${this.examId}/${this.subjectId}/${this.studentAnswer.id}`
-            blobTool.upload(markPng, path).then(
+            blobTool.upload(markPng, {path}).then(
                 res => {
                     if (!hasMarked) {
                         this.studentAnswer.mark[this.curAnIndex].push({
@@ -769,14 +770,14 @@ export default {
             async handler(newValue, oldValue) {
                 this.studentAnswer = this._.cloneDeep(newValue || {})
                 console.log('学生作答数据', this.studentAnswer)
-                
+
                 //处理默认显示批注
                 this.markFlag = {}
                 if (this.studentAnswer.mark) {
                     //后端阅卷批注数据异常,暂时这里过滤处理
-                    for(let i = 0; i < this.studentAnswer.mark.length; i++){
-                        if(this.studentAnswer.mark[i]){
-                            this.studentAnswer.mark[i] = this.studentAnswer.mark[i].filter(m=>{
+                    for (let i = 0; i < this.studentAnswer.mark.length; i++) {
+                        if (this.studentAnswer.mark[i]) {
+                            this.studentAnswer.mark[i] = this.studentAnswer.mark[i].filter(m => {
                                 return !!m.mark
                             })
                         }
@@ -801,7 +802,7 @@ export default {
                              * 2、这里就直接读取原始作答数据;
                              * 3、在渲染的时候再判断当前题目是否有批注数据。
                              */
-                            
+
                             a = await this.$tools.getFile(`${blobUrl}/exam/${this.studentAnswer.answers[0]}?${sas}`)
                             if (a) {
                                 let ans = JSON.parse(a)
@@ -819,8 +820,8 @@ export default {
                         } catch (e) {
                             console.log('error', e)
                             let full = []
-                            let i = 0 
-                            while(i < this.paperInfo.item.length){
+                            let i = 0
+                            while (i < this.paperInfo.item.length) {
                                 full.push(`<p style="color:red">${this.$t('learnActivity.score.ansErr')}</p>`)
                                 i++
                             }

+ 53 - 34
TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue

@@ -116,7 +116,7 @@
                                     </template>
                                     <template slot-scope="{ row,index }" slot="irs">
                                         <span v-show="editIndex !== index" :style="{color:row.irs ? '#303030':'red'}">{{row.irs || $t('cusMgt.notSet')}}</span>
-                                        <InputNumber :min="0" v-model="editIrs" v-show="editIndex == index" style="width: 60px;"></InputNumber>
+                                        <InputNumber :min="1" v-model="editIrs" v-show="editIndex == index" style="width: 60px;"></InputNumber>
                                         <Icon type="md-checkmark" v-show="editIndex == index" @click="confirmSetNo(row,index)" class="reset-no-btn" />
                                         <Icon type="md-close" v-show="editIndex == index" @click="cancelSetNo()" class="reset-no-btn" />
                                     </template>
@@ -129,7 +129,6 @@
                                     <template slot-scope="{ row,index }" slot="action">
                                         <div class="item-tools">
                                             <Icon type="md-create" size="18" style="cursor:pointer;margin-left:10px" :title="$t('schoolBaseInfo.noSetLabel')" @click="setNo(row,index)" />
-                                            <!-- <Icon type="md-trash" size="18" style="cursor:pointer;margin-left:10px" :title="$t('schoolBaseInfo.noSetLabel')" @click="setNo(row,index)" /> -->
                                         </div>
                                     </template>
                                 </Table>
@@ -494,9 +493,20 @@ export default {
                 // },
                 {
                     title: this.$t('courseManage.classroom.studentTableC9'),
+                    key: 'irs',
                     slot: 'irs',
                     align: 'center',
-                    sortable: true
+                    sortable: true,
+                    sortMethod: (a, b, type) => {
+                        if(!b){
+                            return -1
+                        }
+                        if (type == 'desc') {
+                            return parseInt(a) > parseInt(b) ? -1 : 1
+                        } else {
+                            return parseInt(a) < parseInt(b) ? -1 : 1
+                        }
+                    }
                 },
                 {
                     title: ' ',
@@ -553,7 +563,7 @@ export default {
             // this.viewRepStatus = true
             // this.viewType = 'video'
             this.$router.push({
-                name:'teachCenter'
+                name: 'teachCenter'
             })
         },
         //查看电子笔记
@@ -573,7 +583,7 @@ export default {
         },
         //根据时长换算时间
         handleDuration(duration) {
-            if(!duration) return this.$t('cusMgt.noData')
+            if (!duration) return this.$t('cusMgt.noData')
             let calc = duration
             //天
             let dayC = 24 * 60 * 60
@@ -607,31 +617,6 @@ export default {
                 this.btnLoading = false
             })
         },
-        confirmSetNo(row, rowIndex) {
-            //检查irs重复
-            let irsRep = this.students.some((item, index) => {
-                return index != rowIndex && item.irs == this.editIrs
-            })
-            if (irsRep) {
-                this.$Message.warning(this.$t('schoolBaseInfo.irsRep'))
-                return
-            }
-            this.editIndex = -1
-            let schoolId = this.$store.state.userInfo.schoolCode
-            row.irs = this.editIrs + ''
-            let data = [row]
-            this.tableLoading = true
-            this.$api.stuAccount.updStudent(schoolId, data).then(
-                res => {
-                    this.$Message.success(this.$t('schoolBaseInfo.updOk'))
-                },
-                err => {
-                    this.$Message.error(this.$t('schoolBaseInfo.updErr'))
-                }
-            ).finally(() => {
-                this.tableLoading = false
-            })
-        },
         cancelSetNo() {
             this.editIrs = null
             this.editIndex = -1
@@ -715,7 +700,7 @@ export default {
                 this.getActivityList()
             } else if (this.tabName == 'stus') {
                 this.getStuList()
-            }else if(this.tabName == 'record'){
+            } else if (this.tabName == 'record') {
                 this.getRecordList()
             }
         },
@@ -1021,6 +1006,38 @@ export default {
             }
 
         },
+        confirmSetNo(row, rowIndex) {
+            if (!this.editIrs) {
+                this.$Message.warning(this.$t('schoolBaseInfo.setIrsWarning'))
+                return
+            }
+            //检查irs重复
+            let irsRep = this.students.some((item, index) => {
+                return index != rowIndex && item.irs == this.editIrs
+            })
+            if (irsRep) {
+                this.$Message.warning(this.$t('schoolBaseInfo.irsRep'))
+                return
+            }
+
+            // 当前名单对应的课程安排用于更新UI
+            let schedule = this.courseListShow[this.curCusIndex].schedule.find(item => {
+                return item.stulist == this.teaClassList[this.curClassIndex].stulist && !item.classId //只有自定名单能添加学生,所以classId == ‘’
+            })
+            let stulist = this.groupList.find(item => {
+                return item.id == this.teaClassList[this.curClassIndex].stulist
+            })
+            if (stulist) {
+                stulist.members.forEach((item, index) => {
+                    item.irs = (index + 1) + ''
+                })
+                let s = stulist.members.find(item=>item.id == row.id)
+                s.irs = this.editIrs + ''
+                schedule.allStu = stulist.members
+                this.saveStuList(stulist)
+            }
+            this.editIndex = -1
+        },
         // 批量设置irs
         confirmFastSet() {
             // 当前名单对应的课程安排用于更新UI
@@ -1042,7 +1059,9 @@ export default {
             let defIRS = stulist.members.length + 1
             let irs = stulist.members.map(item => item.irs)
             irs = irs.filter(item => !!item)
-            irs.sort()
+            irs.sort((a, b) => {
+                return parseInt(a) - parseInt(b) > 0 ? 1 : -1
+            })
             for (let index = 0; index < irs.length; index++) {
                 if ((index + 1) != irs[index]) {
                     defIRS = index + 1
@@ -1401,7 +1420,7 @@ export default {
             } else {
                 this.changeClassroom(0)
             }
-            if(this.tabName == 'record'){
+            if (this.tabName == 'record') {
                 this.getRecordList()
             }
         },
@@ -1645,7 +1664,7 @@ export default {
                 res => {
                     this.recordList = res.lessonRecords
                     // 这里先暂时处理id为这个,只有这个blob才有数据
-                    this.recordList.forEach(item=>{
+                    this.recordList.forEach(item => {
                         item.id = '256246355239899136'
                     })
                     let privateSas = {}

+ 1 - 1
TEAMModelOS/ClientApp/src/view/newsheet/index.vue

@@ -425,7 +425,7 @@
 						`paper/${paperInfo.name}`
 					try {
 						// 等待上传blob的返回结果
-						let blobFile = await containerClient.upload(file, path)
+						let blobFile = await containerClient.upload(file, { path:path })
 						if (blobFile.blob) {
 							r(200)
 						} else {

+ 14 - 6
TEAMModelOS/ClientApp/src/view/questionnaire/ManageQuestionnaire.vue

@@ -558,8 +558,12 @@
 						qnBaseInfo.slides = itemUrls
 						let file = new File([JSON.stringify(qnBaseInfo)], "index.json");
 						// 等待上传blob的返回结果
-						let blobFile = await containerClient.upload(file,
-						`${areaId}/survey/${qnBaseInfo.id}`, {}, false, `${areaId}/`);
+						let blobFile = await containerClient.upload(file,{
+							path:`${areaId}/survey/${qnBaseInfo.id}`,
+							checkSize:false,
+							root:`${areaId}/`
+						})
+						
 						if (blobFile.blob) {
 							delete qnBaseInfo.slides
 							resolve(blobFile.blob)
@@ -586,7 +590,12 @@
 							let file = new File([JSON.stringify(item)], curId + ".json");
 							try {
 								// 等待上传blob的返回结果
-								let blobFile = await containerClient.upload(file, `${areaId}/survey/${qnBaseInfo.id}`,{} , false,`${areaId}/`);
+								// let blobFile = await containerClient.upload(file, `${areaId}/survey/${qnBaseInfo.id}`,{} , false,`${areaId}/`);
+								let blobFile = await containerClient.upload(file,{
+									path:`${areaId}/survey/${qnBaseInfo.id}`,
+									checkSize:false,
+									root:`${areaId}/`
+								})
 								if (blobFile.blob) {
 									console.log('上传Blob成功', blobFile)
 									r(blobFile.blob)
@@ -629,8 +638,7 @@
 							let file = new File([JSON.stringify(item)], curId + ".json");
 							try {
 								// 等待上传blob的返回结果
-								let blobFile = await containerClient.upload(file,
-									'survey/' + qnBaseInfo.id);
+								let blobFile = await containerClient.upload(file,{ path:'survey/' + qnBaseInfo.id });
 								if (blobFile.blob) {
 									console.log('上传Blob成功', blobFile)
 									r(blobFile.blob)
@@ -670,7 +678,7 @@
 						);
 						let file = new File([JSON.stringify(qnBaseInfo)], "index.json");
 						// 等待上传blob的返回结果
-						let blobFile = await containerClient.upload(file, 'survey/' + qnBaseInfo.id);
+						let blobFile = await containerClient.upload(file, { path:'survey/' + qnBaseInfo.id});
 						if (blobFile.blob) {
 							delete qnBaseInfo.slides
 							resolve(blobFile.blob)

+ 7 - 3
TEAMModelOS/ClientApp/src/view/resource/Policy.vue

@@ -134,7 +134,7 @@ export default {
             }
         }
         return {
-            isNewTag:false,
+            isNewTag: false,
             previewInfo: {},
             viewStatus: false,
             blobSas: '',
@@ -213,7 +213,11 @@ export default {
             let container = blobUrl.substring(blobUrl.lastIndexOf('/') + 1)
             let containerClient = new BlobTool(host, container, '?' + blobSas, 'school')
             let filePath = `${sessionStorage.getItem('areaId')}/policy`
-            containerClient.upload(file, filePath, {}, false, sessionStorage.getItem('areaId') + '/').then(
+            containerClient.upload(file, {
+                path: filePath,
+                cehckSize: false,
+                root: sessionStorage.getItem('areaId') + '/'
+            }).then(
                 res => {
                     console.log(res)
                     this.file = file
@@ -382,7 +386,7 @@ export default {
             if (tag) {
                 this.policyInfo.tag = tag
                 this.isNewTag = false
-            }else{
+            } else {
                 this.policyInfo.tag = ''
                 this.isNewTag = true
             }

+ 10 - 2
TEAMModelOS/ClientApp/src/view/resource/SourceCenter.vue

@@ -167,7 +167,11 @@ export default {
             let container = blobUrl.substring(blobUrl.lastIndexOf('/') + 1)
             let containerClient = new BlobTool(host, container, '?' + blobSas, 'school')
             let filePath = `${sessionStorage.getItem('areaId')}/policy`
-            containerClient.upload(file, filePath, {}, false, sessionStorage.getItem('areaId') + '/').then(
+            containerClient.upload(file, {
+                path:filePath,
+                checkSize:false,
+                root:sessionStorage.getItem('areaId') + '/'
+            }).then(
                 res => {
                     console.log(res)
                     this.resInfo.thum = res.url
@@ -199,7 +203,11 @@ export default {
             let containerClient = new BlobTool(host, container, '?' + blobSas, 'school')
             let filePath = `${sessionStorage.getItem('areaId')}/policy`
             this.uploading = true
-            containerClient.upload(file, filePath, {}, false, sessionStorage.getItem('areaId') + '/').then(
+            containerClient.upload(file, {
+                path:filePath,
+                checkSize:false,
+                root:sessionStorage.getItem('areaId') + '/'
+            }).then(
                 res => {
                     console.log(res)
                     this.file = file

+ 12 - 10
TEAMModelOS/ClientApp/src/view/schoolmgmt/SystemSetting/SystemSetting.less

@@ -669,13 +669,14 @@
     position: relative;
     cursor: pointer;
     font-weight: 400;
+    color: #c0c0c0;
     &::before{
         content: '';
         font-size: 16px;
         display: block;
         width: fit-content;
         position: absolute;
-        left: -16px;
+        left: -20px;
         top: 3px;
         border-left: 8px solid transparent;
         border-right: 8px solid transparent;
@@ -693,13 +694,14 @@
 }
 .subject-tag-active{
     font-weight: 600;
-    &:first-child{
-        color: #85F9BD;
-    }
-    &:nth-child(2){
-        color:#ff9900;
-    }
-    &:nth-child(3){
-        color:#00A4E9;
-    }
+    color: black;
+    // &:first-child{
+    //     color: #85F9BD;
+    // }
+    // &:nth-child(2){
+    //     color:#ff9900;
+    // }
+    // &:nth-child(3){
+    //     color:#00A4E9;
+    // }
 }

+ 0 - 19
TEAMModelOS/ClientApp/src/view/sso/Index.vue

@@ -25,28 +25,9 @@ export default {
             if (login_schoolCode) localStorage.setItem('login_schoolCode', login_schoolCode)
         },
         toLoginBanding() {
-            // let clientId, accUrl
-            // //国际站
-            // if (this.$store.state.config.srvAdr == 'Global') {
-            //     clientId = this.$store.state.config.Global.clientID
-            //     accUrl = this.$store.state.config.Global.accAPIUrl
-            // }
-            // // 大陆站
-            // else {
-            //     clientId = this.$store.state.config.China.clientID
-            //     accUrl = this.$store.state.config.China.accAPIUrl
-            // }
-            // let callback = decodeURIComponent(window.location.href)
-            // let state = this.$jsFn.getBtwRandom(1000, 9999)
-            // let nonce = this.$jsFn.uuid()
-            // accUrl = process.env.NODE_ENV == 'development' ? 'https://account-rc.teammodel.cn' : accUrl
-            // let loginUrl = `${accUrl}/oauth2/authorize?response_type=code&client_id=${clientId}&state=${state}&nonce=${nonce}&redirect_uri=${encodeURIComponent(callback)}`
-            // this.clearData()
-            // window.location.href = loginUrl
             let queryData = this._.cloneDeep(this.$route.query)
             queryData.loginType = 'trainsso'
             //根据站点判断跳转路由
-            // let path = window.location.host == 'jinniu.teammodel.cn' ? '/login/jinniuteacher' : '/login/teacher'
             this.$router.push({
                 path: '/bandphone',
                 query: queryData

+ 33 - 21
TEAMModelOS/ClientApp/src/view/statistics/Dashboard.vue

@@ -129,14 +129,14 @@
                     <PersonalPhoto :name="item.name" :picture="item.picture" />
                     <span class="teacher-name">{{item.name}}</span>
                     <span class="hour-count-wrap">
-                        <Icon custom="iconfont icon-online" title="线上研修学时" :color="item.onlineTime == 0 ? '#17233d' : item.onlineTime >= 20 ? '#19be6b' : '#17233d'"/>
-                        <span class="teacher-hour-num" :style="{color:item.onlineTime == 0 ? '#17233d' : item.onlineTime >= 20 ? '#19be6b' : '#17233d'}">{{item.onlineTime}}</span>
-                        <Icon custom="iconfont icon-submit" title="认证材料学时"  :color="item.currency.submitTime == 0 ? '#17233d' : item.currency.submitTime >= 15 ? '#19be6b' : '#17233d'"/>
-                        <span class="teacher-hour-num" :style="{color:item.currency.submitTime == 0 ? '#17233d' : item.currency.submitTime >= 15 ? '#19be6b' : '#17233d'}">{{item.currency.submitTime}}</span>
-                        <Icon custom="iconfont icon-offline" title="校本研修学时"  :color="item.offlineTime == 0 ? '#17233d' : item.offlineTime >= 10 ? '#19be6b' : '#17233d'"/>
-                        <span class="teacher-hour-num" :style="{color:item.offlineTime == 0 ? '#17233d' : item.offlineTime >= 10 ? '#19be6b' : '#17233d'}">{{item.offlineTime}}</span>
-                        <Icon custom="iconfont icon-cus-video" title="课堂实录学时"  :color="item.classTime == 0 ? '#17233d' : item.classTime >= 5 ? '#19be6b' : '#17233d'"/>
-                        <span class="teacher-hour-num" :style="{color:item.classTime == 0 ? '#17233d' : item.classTime >= 5 ? '#19be6b' : '#17233d'}">{{item.classTime}}</span>
+                        <Icon custom="iconfont icon-online" title="线上研修学时" :color="item.onlineTime == 0 ? '#17233d' : item.onlineTime >= onlineTime ? '#19be6b' : '#17233d'" />
+                        <span class="teacher-hour-num" :style="{color:item.onlineTime == 0 ? '#17233d' : item.onlineTime >= onlineTime ? '#19be6b' : '#17233d'}">{{item.onlineTime}}</span>
+                        <Icon custom="iconfont icon-submit" title="认证材料学时" :color="item.currency.submitTime == 0 ? '#17233d' : item.currency.submitTime >= submitTime ? '#19be6b' : '#17233d'" />
+                        <span class="teacher-hour-num" :style="{color:item.currency.submitTime == 0 ? '#17233d' : item.currency.submitTime >= submitTime ? '#19be6b' : '#17233d'}">{{item.currency.submitTime}}</span>
+                        <Icon custom="iconfont icon-offline" title="校本研修学时" :color="item.offlineTime == 0 ? '#17233d' : item.offlineTime >= offlineTime ? '#19be6b' : '#17233d'" />
+                        <span class="teacher-hour-num" :style="{color:item.offlineTime == 0 ? '#17233d' : item.offlineTime >= offlineTime ? '#19be6b' : '#17233d'}">{{item.offlineTime}}</span>
+                        <Icon custom="iconfont icon-cus-video" title="课堂实录学时" :color="item.classTime == 0 ? '#17233d' : item.classTime >= videoTime ? '#19be6b' : '#17233d'" />
+                        <span class="teacher-hour-num" :style="{color:item.classTime == 0 ? '#17233d' : item.classTime >= videoTime ? '#19be6b' : '#17233d'}">{{item.classTime}}</span>
                     </span>
                 </div>
             </div>
@@ -160,6 +160,11 @@ export default {
     },
     data() {
         return {
+            onlineTime: 20,
+            offlineTime: 10,
+            videoTime: 5,
+            submitTime: 15,
+            totalTime: 50,
             viewStatus: false,
             viewIndex: 0,
             groupData: [],
@@ -218,11 +223,11 @@ export default {
         }
     },
     methods: {
-        getRate(data){
-            if(this.topData && this.topData[0] && this.topData[0].number){
-                console.log(data,this.topData)
+        getRate(data) {
+            if (this.topData && this.topData[0] && this.topData[0].number) {
+                console.log(data, this.topData)
                 return (data.number / this.topData[0].number * 100).toFixed(0)
-            }else{
+            } else {
                 return 0
             }
         },
@@ -239,6 +244,13 @@ export default {
             this.$api.ability.getSchoolData(params).then(
                 res => {
                     if (!res.error) {
+                        //设置的学时
+                        this.onlineTime = res.setting.onlineTime || this.onlineTime
+                        this.offlineTime = res.setting.offlineTime || this.offlineTime
+                        this.submitTime = res.setting.submitTime || this.submitTime
+                        this.videoTime = res.setting.classTime || this.videoTime
+                        this.totalTime = res.setting.allTime || this.totalTime
+
                         let data = []
                         //参训人数
                         data.push(res.teacherTrains.length)
@@ -269,10 +281,10 @@ export default {
 
                         // 四个维度合格率
                         let joinCount = res.teacherTrains.length
-                        let onlineCount = res.teacherTrains.filter(item => item.onlineTime >= 20).length
-                        let offlineCount = res.teacherTrains.filter(item => item.offlineTime >= 10).length
-                        let submitCount = res.teacherTrains.filter(item => item.currency.submitTime >= 15).length
-                        let classCount = res.teacherTrains.filter(item => item.classTime >= 5).length
+                        let onlineCount = res.teacherTrains.filter(item => item.onlineTime >= this.onlineTime).length
+                        let offlineCount = res.teacherTrains.filter(item => item.offlineTime >= this.offlineTime).length
+                        let submitCount = res.teacherTrains.filter(item => item.currency.submitTime >= this.submitTime).length
+                        let classCount = res.teacherTrains.filter(item => item.classTime >= this.videoTime).length
                         console.log(classCount)
                         this.rate1 = joinCount ? parseInt(onlineCount * 100 / joinCount) : 0
                         this.rate2 = joinCount ? parseInt(offlineCount * 100 / joinCount) : 0
@@ -311,11 +323,11 @@ export default {
                                 name: item[0].groupName,
                                 groupName: item[0].groupName,
                                 members: item,
-                                onlineCount: item.filter(t => t.onlineTime >= 20).length,
-                                uploadCount: item.filter(t => t.currency.submitTime >= 15).length,
-                                offlineCount: item.filter(t => t.offlineTime >= 10).length,
-                                classCount: item.filter(t => t.classTime >= 5).length,
-                                totalCount: item.filter(t => t.totalTime >= 50).length
+                                onlineCount: item.filter(t => t.onlineTime >= this.onlineTime).length,
+                                uploadCount: item.filter(t => t.currency.submitTime >= this.submitTime).length,
+                                offlineCount: item.filter(t => t.offlineTime >= this.offlineTime).length,
+                                classCount: item.filter(t => t.classTime >= this.videoTime).length,
+                                totalCount: item.filter(t => t.totalTime >= this.totalTime).length
                             })
                         })
 

+ 22 - 44
TEAMModelOS/ClientApp/src/view/statistics/TableData.vue

@@ -16,23 +16,23 @@
                     <span>{{row.currency.exerciseAbility}}</span>
                 </template>
                 <template slot-scope="{ row }" slot="online">
-                    <span>{{ `${row.onlineTime > 20 ? 20 : row.onlineTime}/20`}}</span>
+                    <span>{{ `${row.onlineTime > onlineTime ? onlineTime : row.onlineTime}/${onlineTime}`}}</span>
                 </template>
                 <template slot-scope="{ row }" slot="offline">
-                    <span>{{ `${row.offlineTime > 10 ? 10 : row.offlineTime}/10`}}</span>
+                    <span>{{ `${row.offlineTime > offlineTime ? offlineTime : row.offlineTime}/${offlineTime}`}}</span>
                 </template>
                 <template slot-scope="{ row }" slot="assessment">
-                    <span>{{ `${row.currency.submitTime > 15 ? 15 : row.currency.submitTime}/15` }}</span>
+                    <span>{{ `${row.currency.submitTime > submitTime ? submitTime : row.currency.submitTime}/${submitTime}` }}</span>
                 </template>
                 <template slot-scope="{ row }" slot="classRecord">
-                    <span>{{ `${row.classTime > 5 ? 5 : row.classTime}/5` }}</span>
+                    <span>{{ `${row.classTime > videoTime ? videoTime : row.classTime}/${videoTime}` }}</span>
                 </template>
                 <template slot-scope="{ row }" slot="allHour">
-                    <span>{{ `${row.totalTime > 50 ? 50 : row.totalTime}/50` }}</span>
+                    <span>{{ `${row.totalTime > totalTime ? totalTime : row.totalTime}/${totalTime}` }}</span>
                 </template>
                 <template slot-scope="{ row }" slot="status">
-                    <span :style="{color:row.totalTime < 50 ? '#ed4014':'#19be6b'}">
-                        {{ row.totalTime < 50 ? '未完成' : '已完成' }}
+                    <span :style="{color:row.totalTime < totalTime ? '#ed4014':'#19be6b'}">
+                        {{ row.totalTime < totalTime ? '未完成' : '已完成' }}
                     </span>
                 </template>
             </Table>
@@ -48,6 +48,12 @@ export default {
     },
     data() {
         return {
+            onlineTime: 20,
+            offlineTime: 10,
+            videoTime: 5,
+            submitTime: 15,
+            totalTime: 50,
+
             loading: false,
             hourData: [],
             hourDataShow: [],
@@ -71,41 +77,6 @@ export default {
                         return row.groupName === value
                     }
                 },
-                // {
-                //     title: '自我练习成长值',
-                //     slot: 'pointCount',
-                //     align: 'center',
-                //     renderHeader: (h, params) => {
-                //         return h('div', [
-                //             h('strong', '自我练习成长值'),
-                //             h('Tooltip', {
-                //                 props: {
-                //                     placement: 'right',
-                //                     transfer: true,
-                //                     theme: "light"
-                //                 },
-                //             }, [h('Icon', {
-                //                 props: {
-                //                     type: 'md-help-circle',
-                //                 },
-                //                 style: {
-                //                     marginLeft: '5px',
-                //                     fontSize: '16px',
-                //                     cursor: 'pointer'
-                //                 }
-                //             }),
-                //             h('span', {
-                //                 slot: 'content',
-                //                 style: {
-                //                     whiteSpace: 'normal',
-                //                     wordBreak: 'break-all'
-                //                 }
-                //             }, '通过能力点自测获得成长值')
-                //             ])
-
-                //         ])
-                //     }
-                // },
                 {
                     title: '线上研修',
                     key: 'onlineTime',
@@ -200,8 +171,8 @@ export default {
                     offlineTime: item.offlineTime,
                     submitTime: item.currency.submitTime,
                     classTime: item.classTime,
-                    alltime: item.totalTime > 50 ? 50 : item.totalTime,
-                    status: item.totalTime < 50 ? '未完成' : '已完成'
+                    alltime: item.totalTime > this.totalTime ? this.totalTime : item.totalTime,
+                    status: item.totalTime < this.totalTime ? '未完成' : '已完成'
                 }
             })
             const params = {
@@ -221,6 +192,13 @@ export default {
             this.$api.ability.getSchoolData(params).then(
                 res => {
                     if (!res.error) {
+                        //设置的学时
+                        this.onlineTime = res.setting.onlineTime || this.onlineTime
+                        this.offlineTime = res.setting.offlineTime || this.offlineTime
+                        this.submitTime = res.setting.submitTime || this.submitTime
+                        this.videoTime = res.setting.classTime || this.videoTime
+                        this.totalTime = res.setting.allTime || this.totalTime
+
                         //表格数据
                         this.hourData = res.teacherTrains
                         this.hourDataShow = this.hourData

+ 24 - 10
TEAMModelOS/ClientApp/src/view/student-account/class/ClassMgt.vue

@@ -352,15 +352,37 @@ export default {
                 },
                 {
                     title: this.$t('courseManage.classroom.studentTableC1'),
+                    key:'no',
                     slot: 'no',
                     align: 'center',
-                    sortable: true
+                    sortable: true,
+                    sortMethod: (a, b, type) => {
+                        if(!b){
+                            return -1
+                        }
+                        if (type == 'desc') {
+                            return parseInt(a) > parseInt(b) ? -1 : 1
+                        } else {
+                            return parseInt(a) < parseInt(b) ? -1 : 1
+                        }
+                    }
                 },
                 {
                     title: this.$t('courseManage.classroom.studentTableC9'),
+                    key:'irs',
                     slot: 'irs',
                     align: 'center',
-                    sortable: true
+                    sortable: true,
+                    sortMethod: (a, b, type) => {
+                        if(!b){
+                            return -1
+                        }
+                        if (type == 'desc') {
+                            return parseInt(a) > parseInt(b) ? -1 : 1
+                        } else {
+                            return parseInt(a) < parseInt(b) ? -1 : 1
+                        }
+                    }
                 },
                 {
                     title: ' ',
@@ -625,10 +647,6 @@ export default {
             let isRepeat = this.students.some((item, index) => {
                 return index != this.editIndex && item.irs == this.editIrs
             })
-            // let irsList = this.students.map(item => item.irs)
-            // let irsRep = irsList.some((item, index) => {
-            //     return !!item && irsList.indexOf(item) != index
-            // })
             if (isRepeat) {
                 this.$Message.warning(this.$t('schoolBaseInfo.irsRep'))
                 return
@@ -637,10 +655,6 @@ export default {
             let noRepeat = this.students.some((item, index) => {
                 return index != this.editIndex && item.no == this.editNo
             })
-            // let noList = this.students.map(item => item.no)
-            // let noRep = noList.some((item, index) => {
-            //     return !!item && noList.indexOf(item) != index
-            // })
             if (noRepeat) {
                 this.$Message.warning(this.$t('schoolBaseInfo.noRep'))
                 return

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

@@ -23,7 +23,7 @@
     }
     .list-content{
         width: 100%;
-        height: 100%;
+        height: ~"calc(100% - 50px)";
     }
     .list-item{
         cursor: pointer;
@@ -102,7 +102,7 @@
     display:none;
 }
 .stu-list-table{
-    height: ~"calc(100% - 45px)";
+    height: ~"calc(100% - 100px)";
     padding: 0 15px;
 }
 .reset-no-btn{

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

@@ -208,6 +208,9 @@ export default {
                     sortable: true,
                     sortMethod: (a, b, type) => {
                         console.log(arguments)
+                        if(!b){
+                            return -1
+                        }
                         if (type == 'desc') {
                             return parseInt(a) > parseInt(b) ? -1 : 1
                         } else {
@@ -402,7 +405,9 @@ export default {
             let defIRS = this.stuListShow[this.curIndex].members.length + 1
             let irs = this.stuListShow[this.curIndex].members.map(item => item.irs)
             irs = irs.filter(item => !!item)
-            irs.sort()
+            irs.sort((a, b) => {
+                return parseInt(a) > parseInt(b) ? 1 : -1
+            })
             for (let index = 0; index < irs.length; index++) {
                 if ((index + 1) != irs[index]) {
                     defIRS = index + 1

+ 18 - 18
TEAMModelOS/ClientApp/src/view/syllabus/Syllabus.vue

@@ -87,14 +87,14 @@
 									</p>
 									<p class="volume-item-info" v-if="inShareView && volume.isDel" style="margin-top: 10px;">
 										<span style="display: flex;align-items: center;">
-											册别已被分享者 {{ volume.creatorName }} 删除
+											{{ $t('syllabus.delTip1') }} {{ volume.creatorName }} {{ $t('syllabus.delete') }}
 										</span>
 									</p>
 									<p class="volume-item-tools" v-if="!isSchool">
-										<Icon type="md-share" title="分享"
+										<Icon type="md-share" :title="$t('syllabus.share')"
 											v-if="!inShareView && activeVolumeIndex === volumeIndex" @click="doShare" />
-										<Icon type="ios-copy" title="收藏" v-if="inShareView && !volume.isDel" @click="doCopy" />
-										<Icon type="md-trash" title="忽略" v-if="inShareView" @click.stop="onDeleteShareVolume(volume)"/>
+										<Icon type="ios-copy" :title="$t('syllabus.save')" v-if="inShareView && !volume.isDel" @click="doCopy" />
+										<Icon type="md-trash" :title="$t('syllabus.ignore')" v-if="inShareView" @click.stop="onDeleteShareVolume(volume)"/>
 									</p>
 								</div>
 							</transition-group>
@@ -279,20 +279,20 @@
 		<Modal v-model="isShareModal" width="1200" footer-hide class="share-syllabus-modal"
 			@on-visible-change="onShareModalChange">
 			<div class="modal-header" slot="header">
-				{{ isSchool ? $t('syllabus.chooseCoTeacher') : `分享个人课纲` }}
+				{{ isSchool ? $t('syllabus.chooseCoTeacher') : $t('syllabus.shareSyllabus') }}
 			</div>
 			<div class="share-wrap">
 				<div class="share-left">
-					<p>1. 选择分享的章节</p>
+					<p>1. {{ $t('syllabus.chooseShareChapter') }}</p>
 					<br>
-					<Checkbox v-model="selectAll" @on-change="onSelectAllChange">整册分享</Checkbox>
+					<Checkbox v-model="selectAll" @on-change="onSelectAllChange">{{ $t('syllabus.allShare') }}</Checkbox>
 					<CheckboxGroup v-model="selectedChapters">
 						<Checkbox v-for="(chapter,index) in treeOrigin" :label="chapter.trees[0].id" border>
 							{{ chapter.trees[0].title }}</Checkbox>
 					</CheckboxGroup>
 				</div>
 				<div class="share-right">
-					<p>2. 选择分享的教师</p>
+					<p>2. {{ $t('syllabus.chooseTeacher') }}</p>
 					<InviteTeacher :selectedChapters="selectedChapters" :authIds="curVolume.auth.map(i => i.tmdid)"
 						ref="inviteRef" v-if="isShareModal"></InviteTeacher>
 				</div>
@@ -302,44 +302,44 @@
 		<Modal v-model="isCopyModal" width="1200" footer-hide class="share-syllabus-modal"
 			@on-visible-change="onShareModalChange">
 			<div class="modal-header" slot="header">
-				{{ isSchool ? $t('syllabus.chooseCoTeacher') : `收藏分享课纲` }}
+				{{ isSchool ? $t('syllabus.chooseCoTeacher') : $t('syllabus.saveSyllabus') }}
 			</div>
 			<div class="share-wrap">
 				<div class="share-left">
-					<p>1. 选择要收藏的章节</p>
+					<p>1. {{ $t('syllabus.chooseSaveSyllabus') }}</p>
 					<br>
-					<Checkbox v-model="selectAll" @on-change="onSelectAllChange">整册收藏</Checkbox>
+					<Checkbox v-model="selectAll" @on-change="onSelectAllChange">{{ $t('syllabus.allSave') }}</Checkbox>
 					<CheckboxGroup v-model="selectedChapters">
 						<Checkbox v-for="(chapter,index) in treeOrigin" :label="chapter.trees[0].id" border>
 							{{ chapter.trees[0].title }}</Checkbox>
 					</CheckboxGroup>
 				</div>
 				<div class="share-right">
-					<p>2. 选择收藏位置</p>
+					<p>2. {{ $t('syllabus.chooseSavePos') }}</p>
 					<div class="copy-blocks">
 						<div :class="['copy-block-item',activeCopyIndex === 0 ? 'copy-block-item-active' : '']"
 							@click="activeCopyIndex = 0">
 							<Icon type="md-git-compare" />
-							<span>已有册别</span>
+							<span>{{ $t('syllabus.pos1') }}</span>
 						</div>
 						<div :class="['copy-block-item',activeCopyIndex === 1 ? 'copy-block-item-active' : '']"
 							@click="activeCopyIndex = 1">
 							<Icon type="md-add" />
-							<span>新建册别</span>
+							<span>{{ $t('syllabus.pos2') }}</span>
 						</div>
 					</div>
 					<div style="margin-top: 20px;margin-left: 5px;" v-if="activeCopyIndex === 0">
-						<p>选择一个册别</p>
+						<p>{{ $t('syllabus.chooseVolume') }}</p>
 						<Select v-model="copyTargetVolumeIndex" style="width: 500px;margin-top: 10px;">
 							<Option v-for="(item,index) in myVolumeList" :value="index" :key="index">{{item.name}}
 							</Option>
 						</Select>
 					</div>
 					<div style="margin-top: 20px;margin-left: 5px;" v-if="activeCopyIndex === 1">
-						<p>输入新册别名称</p>
+						<p>{{ $t('syllabus.newVolume') }}</p>
 						<Input autofocus v-model="newVolumeName" style="width: 500px;margin-top: 20px;"></Input>
 					</div>
-					<Button type="primary" @click="sendCopyApi" :loading="isCopyBtnLoading">确认收藏</Button>
+					<Button type="primary" @click="sendCopyApi" :loading="isCopyBtnLoading">{{ $t('syllabus.confirmSave') }}</Button>
 				</div>
 			</div>
 		</Modal>
@@ -1598,7 +1598,7 @@
 							// 先把对应试题目录下的全部复制到校本BLOB 然后再更新添加学段科目等字段后的题目Json文件
 							toClient.copyFolder(targetPath, sourcePath, fromClient).then(async res => {
 								try {
-									let blobFile = await toClient.upload(file, pId ? `syllabus/${this.curNode.id}/${pId}` : targetPrefix + pItem.id);
+									let blobFile = await toClient.upload(file, { path:pId ? `syllabus/${this.curNode.id}/${pId}` : targetPrefix + pItem.id });
 									if (blobFile.blob) {
 										if (isSaveToItem) {
 											this.saveExercise(pItem).then(result => {

+ 13 - 11
TEAMModelOS/ClientApp/src/view/task/mark/ByQu.vue

@@ -21,7 +21,7 @@
                     {{$t('learnActivity.mark.toggleQu')}}
                 </span>
                 <span class="action-btn" @click="viewOriginal" v-show="taskInfo && taskInfo.source === '2'">
-                    <Icon type="md-eye"  class="action-btn-icon"/>
+                    <Icon type="md-eye" class="action-btn-icon" />
                     {{$t('learnActivity.score.viewOrigin')}}
                 </span>
                 <span class="action-btn" @click="errStatus = true">
@@ -154,11 +154,11 @@ export default {
     },
     data() {
         return {
-            originalStatus:false,
-            sourceList:[],
+            originalStatus: false,
+            sourceList: [],
             isComplete: false,
             loading: true,
-            errText:'',
+            errText: '',
             errReason: 1,
             errStatus: false,
             score: null,
@@ -185,8 +185,8 @@ export default {
         viewOriginal() {
             console.log(this.stusInfo)
             let stuInfo = this.stusInfo[this.stuIndex]
-            let sas = this.$store.state.user.schoolProfile.blob_sas 
-            let blobUrl = JSON.parse(decodeURIComponent(localStorage.school_profile, "utf-8")).blob_uri 
+            let sas = this.$store.state.user.schoolProfile.blob_sas
+            let blobUrl = JSON.parse(decodeURIComponent(localStorage.school_profile, "utf-8")).blob_uri
             let host = blobUrl.substring(0, blobUrl.lastIndexOf('/'))
             let cont = blobUrl.substring(blobUrl.lastIndexOf('/') + 1)
             let blobTool = new BlobTool(host, cont, '?' + sas, 'school')
@@ -322,7 +322,9 @@ export default {
                     let blobTool = new BlobTool(host, cont, '?' + sas, 'school')
                     path = `exam/${this.taskInfo.cid}/${this.taskInfo.subject}/${this.stuId}`
                     this.markImg = undefined
-                    blobTool.upload(markPng, path).then(
+                    blobTool.upload(markPng, {
+                        path: path
+                    }).then(
                         res => {
                             this.$Message.success(this.$t('learnActivity.mark.markSaveOk'))
                         },
@@ -332,7 +334,7 @@ export default {
                     )
                     this.stusInfo[this.stuIndex].markArr.splice(this.quIndex, 1, `${path}/${fileName}`)
                 }
-                console.log('学生数据',this.stusInfo)
+                console.log('学生数据', this.stusInfo)
                 let requstData = {
                     id: this.taskInfo.cid,
                     stuId: this.stusInfo[this.stuIndex].stuId,
@@ -437,10 +439,10 @@ export default {
                         this.stusInfo.push({
                             stuId: res.stuId,
                             answer: ansBlob ? await this.$tools.getFile(`${blobUrl}/exam/${ansBlob}?${sas}`) : [],
-                            score: res.item.map(i=>{
+                            score: res.item.map(i => {
                                 return i.sc
                             }),
-                            markArr: res.item.map(i=>{
+                            markArr: res.item.map(i => {
                                 return i.blob
                             })
                         })
@@ -528,7 +530,7 @@ export default {
             let sInfo = this.quNoList[this.quIndex]
             score = parseInt(sInfo.score || score)
             let arr = Array.from(new Array(score + 1).keys())
-            if(sInfo.score && sInfo.score != score){
+            if (sInfo.score && sInfo.score != score) {
                 arr.push(sInfo.score)
             }
             return arr

+ 0 - 0
TEAMModelOS/ClientApp/src/view/task/mark/ByQu2.vue


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.