Parcourir la source

Merge branch 'develop6.0-tmd' of http://52.130.252.100:10000/TEAMMODEL/TEAMModelOS into develop6.0-tmd

zhouj1203@hotmail.com il y a 3 ans
Parent
commit
d1acc3f6ee
60 fichiers modifiés avec 1403 ajouts et 1173 suppressions
  1. 2 2
      TEAMModelBI/ClientApp/src/App.vue
  2. BIN
      TEAMModelBI/ClientApp/src/assets/img/loading2.gif
  3. BIN
      TEAMModelBI/ClientApp/src/assets/img/loadingss.gif
  4. 1 1
      TEAMModelBI/ClientApp/src/components/AbilityTree.vue
  5. 0 439
      TEAMModelBI/ClientApp/src/components/loading/fullscreen.vue
  6. 102 120
      TEAMModelBI/ClientApp/src/components/loading/partial.vue
  7. 6 0
      TEAMModelBI/ClientApp/src/language/lang/lang/zh-cn.js
  8. 6 3
      TEAMModelBI/ClientApp/src/view/created/created.vue
  9. 15 0
      TEAMModelBI/ClientApp/src/view/home.vue
  10. 18 0
      TEAMModelBI/ClientApp/src/view/index/dashboard.vue
  11. 4 2
      TEAMModelBI/ClientApp/src/view/index/operateLog.vue
  12. 3 1
      TEAMModelBI/ClientApp/src/view/login.vue
  13. 6 3
      TEAMModelBI/ClientApp/src/view/teachermanage/areamanage.vue
  14. 2 2
      TEAMModelBI/ClientApp/src/view/teachermanage/manage.vue
  15. 4 4
      TEAMModelBI/ClientApp/src/view/teachermanage/school.vue
  16. 3 3
      TEAMModelBI/ClientApp/src/view/teachermanage/traitmanage.vue
  17. 46 44
      TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs
  18. 3 3
      TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj
  19. 75 164
      TEAMModelOS.SDK/Models/Cosmos/Common/LessonRecord.cs
  20. 6 2
      TEAMModelOS/ClientApp/src/api/http.js
  21. 159 0
      TEAMModelOS/ClientApp/src/common/QrcodeModal.vue
  22. 1 1
      TEAMModelOS/ClientApp/src/components/evaluation/ExerciseList.vue
  23. 1 1
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/ClassmateCommentPages.vue
  24. 1 1
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/Homework.vue
  25. 1 1
      TEAMModelOS/ClientApp/src/components/student-web/EventView/EventContentTypeTemplate/LessonTestReport.vue
  26. 35 0
      TEAMModelOS/ClientApp/src/css/common-style.less
  27. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/cusMgt.js
  28. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/cusMgt.js
  29. 2 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/syllabus.js
  30. 1 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/cusMgt.js
  31. 2 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/syllabus.js
  32. 4 0
      TEAMModelOS/ClientApp/src/router/routes.js
  33. 2 2
      TEAMModelOS/ClientApp/src/utils/editorTools.js
  34. 1 1
      TEAMModelOS/ClientApp/src/view/abilityMgmt/Index.vue
  35. 5 5
      TEAMModelOS/ClientApp/src/view/areatrain/TrainDetail.vue
  36. 1 1
      TEAMModelOS/ClientApp/src/view/auth/Product.vue
  37. 1 1
      TEAMModelOS/ClientApp/src/view/evaluation/bank/ExerciseList.vue
  38. 162 16
      TEAMModelOS/ClientApp/src/view/evaluation/bank/PaperDownload.vue
  39. 1 1
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseChild.vue
  40. 1 1
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseExerciseList.vue
  41. 1 1
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseRepair.vue
  42. 2 1
      TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue
  43. 1 1
      TEAMModelOS/ClientApp/src/view/jyzx/index.vue
  44. 34 20
      TEAMModelOS/ClientApp/src/view/learnactivity/MgtPrivEva.vue
  45. 34 10
      TEAMModelOS/ClientApp/src/view/learnactivity/MgtSchoolEva.vue
  46. 1 1
      TEAMModelOS/ClientApp/src/view/login/Index.vue
  47. 5 38
      TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.less
  48. 198 201
      TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue
  49. 287 0
      TEAMModelOS/ClientApp/src/view/shareSyllabus/ShareSyllabus.vue
  50. 27 25
      TEAMModelOS/ClientApp/src/view/sso/Index.vue
  51. 19 15
      TEAMModelOS/ClientApp/src/view/syllabus/Syllabus.vue
  52. 1 1
      TEAMModelOS/ClientApp/src/view/teachermgmt/components/personnel/Index.vue
  53. 6 6
      TEAMModelOS/ClientApp/src/view/train/Create.vue
  54. 4 4
      TEAMModelOS/ClientApp/src/view/train/TrainDetail.vue
  55. 2 2
      TEAMModelOS/Controllers/Both/LessonRecordController.cs
  56. 10 12
      TEAMModelOS/Controllers/Client/HiTeachController.cs
  57. 67 3
      TEAMModelOS/Controllers/Teacher/TeacherCommonController.cs
  58. 3 1
      TEAMModelOS/Controllers/Third/Sc/ScDataInitController.cs
  59. 13 3
      TEAMModelOS/Controllers/XTest/TestController.cs
  60. 3 3
      TEAMModelOS/TEAMModelOS.csproj

+ 2 - 2
TEAMModelBI/ClientApp/src/App.vue

@@ -4,9 +4,9 @@
 
 <script>
 export default {
-    name: "App",
+    name: 'App',
     components: {},
-};
+}
 </script>
 <style>
 #app {

BIN
TEAMModelBI/ClientApp/src/assets/img/loading2.gif


BIN
TEAMModelBI/ClientApp/src/assets/img/loadingss.gif


+ 1 - 1
TEAMModelBI/ClientApp/src/components/AbilityTree.vue

@@ -798,7 +798,7 @@ export default {
     margin-top: 8%;
 }
 .upload-demo {
-    text-align: center;
+    text-align: center !important;
 }
 .upload-submitbtn {
     width: 85%;

+ 0 - 439
TEAMModelBI/ClientApp/src/components/loading/fullscreen.vue

@@ -1,439 +0,0 @@
-<template>
-    <!-- <div class="cssload-loader-inner">
-        <div class="cssload-cssload-loader-line-wrap-wrap">
-            <div class="cssload-loader-line-wrap"></div>
-        </div>
-        <div class="cssload-cssload-loader-line-wrap-wrap">
-            <div class="cssload-loader-line-wrap"></div>
-        </div>
-        <div class="cssload-cssload-loader-line-wrap-wrap">
-            <div class="cssload-loader-line-wrap"></div>
-        </div>
-        <div class="cssload-cssload-loader-line-wrap-wrap">
-            <div class="cssload-loader-line-wrap"></div>
-        </div>
-        <div class="cssload-cssload-loader-line-wrap-wrap">
-            <div class="cssload-loader-line-wrap"></div>
-        </div>
-    </div> -->
-    <div class="cssload-wrap">
-        <div class="translate">
-            <div class="scale"></div>
-        </div>
-    </div>
-    <div class="cssload-wrap">
-        <div class="translate">
-            <div class="scale"></div>
-        </div>
-    </div>
-    <div class="cssload-wrap">
-        <div class="translate">
-            <div class="scale"></div>
-        </div>
-    </div>
-    <div class="cssload-wrap">
-        <div class="translate">
-            <div class="scale"></div>
-        </div>
-    </div>
-    <div class="cssload-wrap">
-        <div class="translate">
-            <div class="scale"></div>
-        </div>
-    </div>
-    <div class="cssload-wrap">
-        <div class="translate">
-            <div class="scale"></div>
-        </div>
-    </div>
-    <div class="cssload-wrap">
-        <div class="translate">
-            <div class="scale"></div>
-        </div>
-    </div>
-    <div class="cssload-wrap">
-        <div class="translate">
-            <div class="scale"></div>
-        </div>
-    </div>
-    <div class="cssload-wrap">
-        <div class="translate">
-            <div class="scale"></div>
-        </div>
-    </div>
-</template>
-<style scoped>
-.cssload-wrap {
-    bottom: 0;
-    left: 0;
-    margin: auto;
-    position: absolute;
-    right: 0;
-    top: 0;
-}
-
-.translate {
-    animation: translate 2300ms cubic-bezier(0.6, -0.28, 0.735, 0.045) infinite;
-    -o-animation: translate 2300ms cubic-bezier(0.6, -0.28, 0.735, 0.045) infinite;
-    -ms-animation: translate 2300ms cubic-bezier(0.6, -0.28, 0.735, 0.045) infinite;
-    -webkit-animation: translate 2300ms cubic-bezier(0.6, -0.28, 0.735, 0.045) infinite;
-    -moz-animation: translate 2300ms cubic-bezier(0.6, -0.28, 0.735, 0.045) infinite;
-    bottom: 0;
-    height: 14px;
-    left: 0;
-    margin: auto;
-    position: absolute;
-    right: 0;
-    top: 0;
-    width: 14px;
-}
-
-.scale {
-    animation: scale 2300ms cubic-bezier(0.6, -0.28, 0.735, 0.045) infinite;
-    -o-animation: scale 2300ms cubic-bezier(0.6, -0.28, 0.735, 0.045) infinite;
-    -ms-animation: scale 2300ms cubic-bezier(0.6, -0.28, 0.735, 0.045) infinite;
-    -webkit-animation: scale 2300ms cubic-bezier(0.6, -0.28, 0.735, 0.045) infinite;
-    -moz-animation: scale 2300ms cubic-bezier(0.6, -0.28, 0.735, 0.045) infinite;
-    height: 100%;
-    width: 100%;
-}
-
-.cssload-wrap:nth-child(1) {
-    transform: rotate(320deg);
-    -o-transform: rotate(320deg);
-    -ms-transform: rotate(320deg);
-    -webkit-transform: rotate(320deg);
-    -moz-transform: rotate(320deg);
-}
-
-.cssload-wrap:nth-child(1) .translate,
-.cssload-wrap:nth-child(1) .scale {
-    animation-delay: 0ms;
-    -o-animation-delay: 0ms;
-    -ms-animation-delay: 0ms;
-    -webkit-animation-delay: 0ms;
-    -moz-animation-delay: 0ms;
-}
-
-.cssload-wrap:nth-child(1) .scale {
-    background: rgb(204, 255, 102);
-}
-
-.cssload-wrap:nth-child(2) {
-    transform: rotate(280deg);
-    -o-transform: rotate(280deg);
-    -ms-transform: rotate(280deg);
-    -webkit-transform: rotate(280deg);
-    -moz-transform: rotate(280deg);
-}
-
-.cssload-wrap:nth-child(2) .translate,
-.cssload-wrap:nth-child(2) .scale {
-    animation-delay: -255.56ms;
-    -o-animation-delay: -255.56ms;
-    -ms-animation-delay: -255.56ms;
-    -webkit-animation-delay: -255.56ms;
-    -moz-animation-delay: -255.56ms;
-}
-
-.cssload-wrap:nth-child(2) .scale {
-    background: rgb(102, 255, 204);
-}
-
-.cssload-wrap:nth-child(3) {
-    transform: rotate(240deg);
-    -o-transform: rotate(240deg);
-    -ms-transform: rotate(240deg);
-    -webkit-transform: rotate(240deg);
-    -moz-transform: rotate(240deg);
-}
-
-.cssload-wrap:nth-child(3) .translate,
-.cssload-wrap:nth-child(3) .scale {
-    animation-delay: -511.11ms;
-    -o-animation-delay: -511.11ms;
-    -ms-animation-delay: -511.11ms;
-    -webkit-animation-delay: -511.11ms;
-    -moz-animation-delay: -511.11ms;
-}
-
-.cssload-wrap:nth-child(3) .scale {
-    background: rgb(102, 102, 255);
-}
-
-.cssload-wrap:nth-child(4) {
-    transform: rotate(200deg);
-    -o-transform: rotate(200deg);
-    -ms-transform: rotate(200deg);
-    -webkit-transform: rotate(200deg);
-    -moz-transform: rotate(200deg);
-}
-
-.cssload-wrap:nth-child(4) .translate,
-.cssload-wrap:nth-child(4) .scale {
-    animation-delay: -766.67ms;
-    -o-animation-delay: -766.67ms;
-    -ms-animation-delay: -766.67ms;
-    -webkit-animation-delay: -766.67ms;
-    -moz-animation-delay: -766.67ms;
-}
-
-.cssload-wrap:nth-child(4) .scale {
-    background: rgb(255, 102, 204);
-}
-
-.cssload-wrap:nth-child(5) {
-    transform: rotate(160deg);
-    -o-transform: rotate(160deg);
-    -ms-transform: rotate(160deg);
-    -webkit-transform: rotate(160deg);
-    -moz-transform: rotate(160deg);
-}
-
-.cssload-wrap:nth-child(5) .translate,
-.cssload-wrap:nth-child(5) .scale {
-    animation-delay: -1022.22ms;
-    -o-animation-delay: -1022.22ms;
-    -ms-animation-delay: -1022.22ms;
-    -webkit-animation-delay: -1022.22ms;
-    -moz-animation-delay: -1022.22ms;
-}
-
-.cssload-wrap:nth-child(5) .scale {
-    background: rgb(255, 204, 102);
-}
-
-.cssload-wrap:nth-child(6) {
-    transform: rotate(120deg);
-    -o-transform: rotate(120deg);
-    -ms-transform: rotate(120deg);
-    -webkit-transform: rotate(120deg);
-    -moz-transform: rotate(120deg);
-}
-
-.cssload-wrap:nth-child(6) .translate,
-.cssload-wrap:nth-child(6) .scale {
-    animation-delay: -1277.78ms;
-    -o-animation-delay: -1277.78ms;
-    -ms-animation-delay: -1277.78ms;
-    -webkit-animation-delay: -1277.78ms;
-    -moz-animation-delay: -1277.78ms;
-}
-
-.cssload-wrap:nth-child(6) .scale {
-    background: rgb(102, 255, 102);
-}
-
-.cssload-wrap:nth-child(7) {
-    transform: rotate(80deg);
-    -o-transform: rotate(80deg);
-    -ms-transform: rotate(80deg);
-    -webkit-transform: rotate(80deg);
-    -moz-transform: rotate(80deg);
-}
-
-.cssload-wrap:nth-child(7) .translate,
-.cssload-wrap:nth-child(7) .scale {
-    animation-delay: -1533.33ms;
-    -o-animation-delay: -1533.33ms;
-    -ms-animation-delay: -1533.33ms;
-    -webkit-animation-delay: -1533.33ms;
-    -moz-animation-delay: -1533.33ms;
-}
-
-.cssload-wrap:nth-child(7) .scale {
-    background: rgb(102, 204, 255);
-}
-
-.cssload-wrap:nth-child(8) {
-    transform: rotate(40deg);
-    -o-transform: rotate(40deg);
-    -ms-transform: rotate(40deg);
-    -webkit-transform: rotate(40deg);
-    -moz-transform: rotate(40deg);
-}
-
-.cssload-wrap:nth-child(8) .translate,
-.cssload-wrap:nth-child(8) .scale {
-    animation-delay: -1788.89ms;
-    -o-animation-delay: -1788.89ms;
-    -ms-animation-delay: -1788.89ms;
-    -webkit-animation-delay: -1788.89ms;
-    -moz-animation-delay: -1788.89ms;
-}
-
-.cssload-wrap:nth-child(8) .scale {
-    background: rgb(204, 102, 255);
-}
-
-.cssload-wrap:nth-child(9) {
-    transform: rotate(0deg);
-    -o-transform: rotate(0deg);
-    -ms-transform: rotate(0deg);
-    -webkit-transform: rotate(0deg);
-    -moz-transform: rotate(0deg);
-}
-
-.cssload-wrap:nth-child(9) .translate,
-.cssload-wrap:nth-child(9) .scale {
-    animation-delay: -2044.44ms;
-    -o-animation-delay: -2044.44ms;
-    -ms-animation-delay: -2044.44ms;
-    -webkit-animation-delay: -2044.44ms;
-    -moz-animation-delay: -2044.44ms;
-}
-
-.cssload-wrap:nth-child(9) .scale {
-    background: rgb(255, 102, 102);
-}
-
-@keyframes translate {
-    0% {
-        transform: translate3d(-600%, 0, 0);
-    }
-    50% {
-        transform: translate3d(600%, 0, 0);
-    }
-    100% {
-        transform: translate3d(-600%, 0, 0);
-    }
-}
-
-@-o-keyframes translate {
-    0% {
-        -o-transform: translate3d(-600%, 0, 0);
-    }
-    50% {
-        -o-transform: translate3d(600%, 0, 0);
-    }
-    100% {
-        -o-transform: translate3d(-600%, 0, 0);
-    }
-}
-
-@-ms-keyframes translate {
-    0% {
-        -ms-transform: translate3d(-600%, 0, 0);
-    }
-    50% {
-        -ms-transform: translate3d(600%, 0, 0);
-    }
-    100% {
-        -ms-transform: translate3d(-600%, 0, 0);
-    }
-}
-
-@-webkit-keyframes translate {
-    0% {
-        -webkit-transform: translate3d(-600%, 0, 0);
-    }
-    50% {
-        -webkit-transform: translate3d(600%, 0, 0);
-    }
-    100% {
-        -webkit-transform: translate3d(-600%, 0, 0);
-    }
-}
-
-@-moz-keyframes translate {
-    0% {
-        -moz-transform: translate3d(-600%, 0, 0);
-    }
-    50% {
-        -moz-transform: translate3d(600%, 0, 0);
-    }
-    100% {
-        -moz-transform: translate3d(-600%, 0, 0);
-    }
-}
-
-@keyframes scale {
-    0% {
-        transform: translateZ(0) scale(0.75, 1);
-    }
-    25% {
-        transform: translateZ(0) scale(1.5, 0.5);
-    }
-    50% {
-        transform: translateZ(0) scale(0.75, 1);
-    }
-    75% {
-        transform: translateZ(0) scale(1.5, 0.5);
-    }
-    100% {
-        transform: translateZ(0) scale(0.75, 1);
-    }
-}
-
-@-o-keyframes scale {
-    0% {
-        -o-transform: translateZ(0) scale(0.75, 1);
-    }
-    25% {
-        -o-transform: translateZ(0) scale(1.5, 0.5);
-    }
-    50% {
-        -o-transform: translateZ(0) scale(0.75, 1);
-    }
-    75% {
-        -o-transform: translateZ(0) scale(1.5, 0.5);
-    }
-    100% {
-        -o-transform: translateZ(0) scale(0.75, 1);
-    }
-}
-
-@-ms-keyframes scale {
-    0% {
-        -ms-transform: translateZ(0) scale(0.75, 1);
-    }
-    25% {
-        -ms-transform: translateZ(0) scale(1.5, 0.5);
-    }
-    50% {
-        -ms-transform: translateZ(0) scale(0.75, 1);
-    }
-    75% {
-        -ms-transform: translateZ(0) scale(1.5, 0.5);
-    }
-    100% {
-        -ms-transform: translateZ(0) scale(0.75, 1);
-    }
-}
-
-@-webkit-keyframes scale {
-    0% {
-        -webkit-transform: translateZ(0) scale(0.75, 1);
-    }
-    25% {
-        -webkit-transform: translateZ(0) scale(1.5, 0.5);
-    }
-    50% {
-        -webkit-transform: translateZ(0) scale(0.75, 1);
-    }
-    75% {
-        -webkit-transform: translateZ(0) scale(1.5, 0.5);
-    }
-    100% {
-        -webkit-transform: translateZ(0) scale(0.75, 1);
-    }
-}
-
-@-moz-keyframes scale {
-    0% {
-        -moz-transform: translateZ(0) scale(0.75, 1);
-    }
-    25% {
-        -moz-transform: translateZ(0) scale(1.5, 0.5);
-    }
-    50% {
-        -moz-transform: translateZ(0) scale(0.75, 1);
-    }
-    75% {
-        -moz-transform: translateZ(0) scale(1.5, 0.5);
-    }
-    100% {
-        -moz-transform: translateZ(0) scale(0.75, 1);
-    }
-}
-</style>

+ 102 - 120
TEAMModelBI/ClientApp/src/components/loading/partial.vue

@@ -13,164 +13,146 @@
     </div>
 </template>
 <style scoped>
-.cssload-container *, .cssload-container *:before, .cssload-container *:after{
-	box-sizing: border-box;
-		-o-box-sizing: border-box;
-		-ms-box-sizing: border-box;
-		-webkit-box-sizing: border-box;
-		-moz-box-sizing: border-box;=
+.cssload-container *,
+.cssload-container *:before,
+.cssload-container *:after {
+    box-sizing: border-box;
+    -o-box-sizing: border-box;
+    -ms-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+    -moz-box-sizing: border-box;
 }
 
 .cssload-container {
-	margin: 49px auto;
-	width: 58px;
-	height: 29px;
+    margin: 0 auto;
+    width: 100px;
+    height: 50px;
 }
 .cssload-container > div {
-	float: left;
-	background: rgb(185,108,255);
-	height: 100%;
-	width: 5px;
-	margin-right: 1px;
-	display: inline-block;
+    float: left;
+    background: rgb(185, 108, 255);
+    height: 100%;
+    width: 5px;
+    margin-right: 1px;
+    display: inline-block;
 }
 
 .cssload-container .cssload-shaft1 {
-	animation-delay: 0.06s;
-		-o-animation-delay: 0.06s;
-		-ms-animation-delay: 0.06s;
-		-webkit-animation-delay: 0.06s;
-		-moz-animation-delay: 0.06s;
+    animation-delay: 0.06s;
+    -o-animation-delay: 0.06s;
+    -ms-animation-delay: 0.06s;
+    -webkit-animation-delay: 0.06s;
+    -moz-animation-delay: 0.06s;
 }
 .cssload-container .cssload-shaft2 {
-	animation-delay: 0.12s;
-		-o-animation-delay: 0.12s;
-		-ms-animation-delay: 0.12s;
-		-webkit-animation-delay: 0.12s;
-		-moz-animation-delay: 0.12s;
+    animation-delay: 0.12s;
+    -o-animation-delay: 0.12s;
+    -ms-animation-delay: 0.12s;
+    -webkit-animation-delay: 0.12s;
+    -moz-animation-delay: 0.12s;
 }
 .cssload-container .cssload-shaft3 {
-	animation-delay: 0.17s;
-		-o-animation-delay: 0.17s;
-		-ms-animation-delay: 0.17s;
-		-webkit-animation-delay: 0.17s;
-		-moz-animation-delay: 0.17s;
+    animation-delay: 0.17s;
+    -o-animation-delay: 0.17s;
+    -ms-animation-delay: 0.17s;
+    -webkit-animation-delay: 0.17s;
+    -moz-animation-delay: 0.17s;
 }
 .cssload-container .cssload-shaft4 {
-	animation-delay: 0.23s;
-		-o-animation-delay: 0.23s;
-		-ms-animation-delay: 0.23s;
-		-webkit-animation-delay: 0.23s;
-		-moz-animation-delay: 0.23s;
+    animation-delay: 0.23s;
+    -o-animation-delay: 0.23s;
+    -ms-animation-delay: 0.23s;
+    -webkit-animation-delay: 0.23s;
+    -moz-animation-delay: 0.23s;
 }
 .cssload-container .cssload-shaft5 {
-	animation-delay: 0.29s;
-		-o-animation-delay: 0.29s;
-		-ms-animation-delay: 0.29s;
-		-webkit-animation-delay: 0.29s;
-		-moz-animation-delay: 0.29s;
+    animation-delay: 0.29s;
+    -o-animation-delay: 0.29s;
+    -ms-animation-delay: 0.29s;
+    -webkit-animation-delay: 0.29s;
+    -moz-animation-delay: 0.29s;
 }
 .cssload-container .cssload-shaft6 {
-	animation-delay: 0.35s;
-		-o-animation-delay: 0.35s;
-		-ms-animation-delay: 0.35s;
-		-webkit-animation-delay: 0.35s;
-		-moz-animation-delay: 0.35s;
+    animation-delay: 0.35s;
+    -o-animation-delay: 0.35s;
+    -ms-animation-delay: 0.35s;
+    -webkit-animation-delay: 0.35s;
+    -moz-animation-delay: 0.35s;
 }
 .cssload-container .cssload-shaft7 {
-	animation-delay: 0.4s;
-		-o-animation-delay: 0.4s;
-		-ms-animation-delay: 0.4s;
-		-webkit-animation-delay: 0.4s;
-		-moz-animation-delay: 0.4s;
+    animation-delay: 0.4s;
+    -o-animation-delay: 0.4s;
+    -ms-animation-delay: 0.4s;
+    -webkit-animation-delay: 0.4s;
+    -moz-animation-delay: 0.4s;
 }
 .cssload-container .cssload-shaft8 {
-	animation-delay: 0.46s;
-		-o-animation-delay: 0.46s;
-		-ms-animation-delay: 0.46s;
-		-webkit-animation-delay: 0.46s;
-		-moz-animation-delay: 0.46s;
+    animation-delay: 0.46s;
+    -o-animation-delay: 0.46s;
+    -ms-animation-delay: 0.46s;
+    -webkit-animation-delay: 0.46s;
+    -moz-animation-delay: 0.46s;
 }
 .cssload-container .cssload-shaft9 {
-	animation-delay: 0.52s;
-		-o-animation-delay: 0.52s;
-		-ms-animation-delay: 0.52s;
-		-webkit-animation-delay: 0.52s;
-		-moz-animation-delay: 0.52s;
+    animation-delay: 0.52s;
+    -o-animation-delay: 0.52s;
+    -ms-animation-delay: 0.52s;
+    -webkit-animation-delay: 0.52s;
+    -moz-animation-delay: 0.52s;
 }
 .cssload-container .cssload-shaft10 {
-	animation-delay: 0.58s;
-		-o-animation-delay: 0.58s;
-		-ms-animation-delay: 0.58s;
-		-webkit-animation-delay: 0.58s;
-		-moz-animation-delay: 0.58s;
+    animation-delay: 0.58s;
+    -o-animation-delay: 0.58s;
+    -ms-animation-delay: 0.58s;
+    -webkit-animation-delay: 0.58s;
+    -moz-animation-delay: 0.58s;
 }
 
-.cssload-container {
-	margin-top: 78px;
-	width: 78px;
-}
 .cssload-container > div {
-	margin-right: 0;
-	animation: cssload-wave 1.73s infinite ease-in-out;
-		-o-animation: cssload-wave 1.73s infinite ease-in-out;
-		-ms-animation: cssload-wave 1.73s infinite ease-in-out;
-		-webkit-animation: cssload-wave 1.73s infinite ease-in-out;
-		-moz-animation: cssload-wave 1.73s infinite ease-in-out;
-	width: 8px;
-	opacity: 0;
-	filter: alpha(opacity=0);
-	transform: scaleY(0.1);
-		-o-transform: scaleY(0.1);
-		-ms-transform: scaleY(0.1);
-		-webkit-transform: scaleY(0.1);
-		-moz-transform: scaleY(0.1);
+    animation: cssload-loading 1.73s infinite ease-in-out;
+    -o-animation: cssload-loading 1.73s infinite ease-in-out;
+    -ms-animation: cssload-loading 1.73s infinite ease-in-out;
+    -webkit-animation: cssload-loading 1.73s infinite ease-in-out;
+    -moz-animation: cssload-loading 1.73s infinite ease-in-out;
+    transform: scaleY(0.05) translateX(-10px);
+    -o-transform: scaleY(0.05) translateX(-10px);
+    -ms-transform: scaleY(0.05) translateX(-10px);
+    -webkit-transform: scaleY(0.05) translateX(-10px);
+    -moz-transform: scaleY(0.05) translateX(-10px);
 }
 
-
-
-@keyframes cssload-wave {
-	50% {
-		transform: scaleY(1.5);
-		background: rgb(86,215,198);
-		opacity: 1;
-		filter: alpha(opacity=100);
-	}
+@keyframes cssload-loading {
+    50% {
+        transform: scaleY(1.2) translateX(10px);
+        background: rgb(86, 215, 198);
+    }
 }
 
-@-o-keyframes cssload-wave {
-	50% {
-		-o-transform: scaleY(1.5);
-		background: rgb(86,215,198);
-		opacity: 1;
-		filter: alpha(opacity=100);
-	}
+@-o-keyframes cssload-loading {
+    50% {
+        -o-transform: scaleY(1.2) translateX(10px);
+        background: rgb(86, 215, 198);
+    }
 }
 
-@-ms-keyframes cssload-wave {
-	50% {
-		-ms-transform: scaleY(1.5);
-		background: rgb(86,215,198);
-		opacity: 1;
-		filter: alpha(opacity=100);
-	}
+@-ms-keyframes cssload-loading {
+    50% {
+        -ms-transform: scaleY(1.2) translateX(10px);
+        background: rgb(86, 215, 198);
+    }
 }
 
-@-webkit-keyframes cssload-wave {
-	50% {
-		-webkit-transform: scaleY(1.5);
-		background: rgb(86,215,198);
-		opacity: 1;
-		filter: alpha(opacity=100);
-	}
+@-webkit-keyframes cssload-loading {
+    50% {
+        -webkit-transform: scaleY(1.2) translateX(10px);
+        background: rgb(86, 215, 198);
+    }
 }
 
-@-moz-keyframes cssload-wave {
-	50% {
-		-moz-transform: scaleY(1.5);
-		background: rgb(86,215,198);
-		opacity: 1;
-		filter: alpha(opacity=100);
-	}
+@-moz-keyframes cssload-loading {
+    50% {
+        -moz-transform: scaleY(1.2) translateX(10px);
+        background: rgb(86, 215, 198);
+    }
 }
 </style>

+ 6 - 0
TEAMModelBI/ClientApp/src/language/lang/lang/zh-cn.js

@@ -0,0 +1,6 @@
+const zh_cn = {
+    login: {
+        title: '钉钉扫码登录',
+    },
+}
+export default zh_cn

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

@@ -195,7 +195,7 @@
             <div class="add-schoolbtn">
                 <el-button @click="addschool">{{$t(`schoolManages.createSchools.addschool`)}}</el-button>
             </div>
-            <div>
+            <div class="confirmarea">
                 <el-button type="primary" @click="createdSchool();createdSchoolLoading=true" :loading="createdSchoolLoading">{{$t(`schoolManages.createSchools.submit`)}}</el-button>
                 <el-button @click="closeandreturn('close','school')">{{$t(`commonMsg.closes`)}}</el-button>
             </div>
@@ -206,7 +206,7 @@
     <el-dialog v-model="batchDialogState" width="75%" :before-close="closeDialog" :close-on-click-modal="false" :close-on-press-escape="false" center>
         <div class="batch-box" v-show="batchList === false">
             <div class="uploadbox">
-                <el-upload class="upload-demo" action="" drag :before-upload="handleBeforeUpload">
+                <el-upload class="upload-demo-school" action="" drag :before-upload="handleBeforeUpload">
                     <svg class="msgicon" aria-hidden="true">
                         <use xlink:href="#icon-mianxingshangchuanwenjian"></use>
                     </svg>
@@ -709,6 +709,7 @@ export default {
     font-size: 22px;
     font-weight: 400;
     border-bottom: 1px dashed #ccc;
+    line-height: 60px;
 }
 .institutionbox {
     min-width: 440px;
@@ -997,7 +998,9 @@ export default {
     text-align: center;
     margin-top: 3%;
 }
-
+.confirmarea {
+    line-height: 40px;
+}
 .province-box,
 .city-box,
 .dist-box {

+ 15 - 0
TEAMModelBI/ClientApp/src/view/home.vue

@@ -19,6 +19,7 @@
 import Header from './common/header.vue'
 import Aside from './common/aside.vue'
 import searchTool from './teachermanage/searchTool.vue'
+
 export default {
     components: {
         Header,
@@ -112,4 +113,18 @@ a:hover {
     -webkit-box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.3);
     background-color: rgba(221, 222, 224); /*滚动条的背景颜色*/
 }
+.el-loading-spinner {
+    margin-top: 0 !important;
+    transform: translateY(-50%);
+}
+.el-loading-text {
+    padding-top: 50px;
+    background-image: url('../assets/img/loading2.gif') !important;
+    background-repeat: no-repeat;
+    background-position: top center;
+    background-size: 75px auto;
+}
+.el-loading-spinner .circular {
+    display: none;
+}
 </style>

+ 18 - 0
TEAMModelBI/ClientApp/src/view/index/dashboard.vue

@@ -727,4 +727,22 @@ ul > li {
         transform: translate(-50%, -50%) rotate(-360deg);
     }
 }
+</style>
+<style>
+.dashebordbox .el-loading-spinner .circular {
+    width: 42px;
+    height: 42px;
+    animation: loading-rotate 1s linear infinite;
+    display: none;
+}
+.dashebordbox .el-loading-spinner {
+    background: url('../../assets/img/loading2.gif') no-repeat;
+    background-size: 48px 48px;
+    width: 100px;
+    height: 100px;
+    position: relative;
+    top: 50%;
+    left: 45%;
+    display: block;
+}
 </style>

+ 4 - 2
TEAMModelBI/ClientApp/src/view/index/operateLog.vue

@@ -71,7 +71,7 @@
             </div> -->
         </div>
         <div class="recordbox">
-            <el-table ref="multipleTableRef" :data="tableData" style="width: 100%" @selection-change="handleSelectionChange" :empty-text='$t(`commonMsg.nodataTable`)'>
+            <el-table ref="multipleTableRef" :data="tableData" style="width: 100%" @selection-change="handleSelectionChange" :empty-text='$t(`commonMsg.nodataTable`)' v-loading="loading" element-loading-text="数据加载中...">
                 <el-table-column prop="index" :label="$t(`log.tables.serialnum`)" sortable align="center" />
                 <el-table-column property="name" :label="$t(`log.tables.name`)" align="center" />
                 <el-table-column property="tmdId" :label="$t(`log.tables.id`)" align="center" />
@@ -105,6 +105,7 @@ export default {
             { id: 2, title: '搜索', icon: '#icon-chaxun', models: 'search' },
             { id: 3, title: '时间日期选择', icon: '#icon-riqi', models: 'time' },
         ])
+        let loading = ref(true)
         //获取所有日志内容
         function getLogcontent(startDate, endDate, platform, model) {
             console.log(startDate, endDate, platform, model, '接收的内容')
@@ -117,6 +118,7 @@ export default {
                 })
                 tableData.value = res.operateLogs
                 model === 'init' ? (originalData.value = res.operateLogs) : ''
+                loading.value = false
             })
         }
         //导出日志
@@ -181,7 +183,7 @@ export default {
             searchKey.value = ''
         }
         getLogcontent('', '', '', 'init')
-        return { tableData, getLogcontent, exportExcel, times, timeChange, cities, changePlatform, Search, searchKey, models, iconGroups, searchkeyword, searchClear }
+        return { tableData, getLogcontent, exportExcel, times, timeChange, cities, changePlatform, Search, searchKey, models, iconGroups, searchkeyword, searchClear, loading }
     },
 }
 </script>

+ 3 - 1
TEAMModelBI/ClientApp/src/view/login.vue

@@ -77,6 +77,7 @@ export default {
             text: '',
             background: '',
         })
+        let loadings = ref(true)
         let msgText = ref('钉钉扫码登录')
         onMounted(() => {
             if (window.location.href.indexOf('?code') != -1) {
@@ -97,7 +98,7 @@ export default {
             let editState = (res) => {
                 loading = ElLoading.service({
                     lock: true,
-                    text: 'Loading',
+                    text: '正在登陆,请稍等...',
                     background: 'rgba(0, 0, 0, 0.7)',
                 })
                 let datas = { code: res }
@@ -209,6 +210,7 @@ export default {
             getOrganization,
             Allpermission,
             loginSuccess,
+            loadings,
         }
     },
 }

+ 6 - 3
TEAMModelBI/ClientApp/src/view/teachermanage/areamanage.vue

@@ -157,7 +157,7 @@
                     </el-button>
                 </div>
             </el-dialog>
-            <el-dialog v-model="CutNotarize" width="50%" :before-close="handleClose">
+            <el-dialog v-model="CutNotarize" width="50%" :before-close="handleClose" :show-close="false">
                 <div class="reminder">注意:<span>{{$t(`areaManages.operational.abilitys.cuthint`)}}</span></div>
                 <div class="cutboxs">
                     <div class="now">
@@ -185,8 +185,9 @@
                 <template #footer>
                     <div class="hint" v-show="loadingForm.cutAbility">
                         <p>{{$t(`areaManages.operational.abilitys.cutTitle`)}}</p>
-                        <el-table v-loading="loadingForm.cutAbility" empty-text="   " style="width: 100%">
-                        </el-table>
+                        <loadingsz></loadingsz>
+                        <!-- <el-table v-loading="loadingForm.cutAbility" empty-text="   " style="width: 100%">
+                        </el-table> -->
                     </div>
                     <div class="cut-footer">
                         <span class="dialog-footer">
@@ -210,10 +211,12 @@ import router from '@/router/index.js'
 import { useRouter } from 'vue-router'
 import Ability from '@/components/Ability.vue'
 import option from '@/static/region.json'
+import loadingsz from '@/components/loading/partial.vue'
 const optionsData = option
 export default {
     components: {
         Ability,
+        loadingsz,
     },
     setup() {
         let { proxy } = getCurrentInstance()

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

@@ -14,7 +14,7 @@
         </el-button>
     </div>
     <div class="manage-table">
-        <el-table :data="tableData.value" style="width: 100%" height="80vh" v-loading="loading" element-loading-text="Loading..." class="customer-table" :empty-text='$t(`personnelManagement.personnelTable.nodatas`)'>
+        <el-table :data="tableData.value" style="width: 100%" height="80vh" v-loading="loading" element-loading-text="数据加载中..." class="customer-table" :empty-text='$t(`personnelManagement.personnelTable.nodatas`)'>
             <el-table-column prop="id" :label="$t(`personnelManagement.personnelTable.serialnum`)" sortable align="center" />
             <el-table-column :label="$t(`personnelManagement.personnelTable.headportrait`)" align="center">
                 <template #default="scope">
@@ -178,7 +178,7 @@ export default {
                           res.ddUserInfos[i].userstate = res.ddUserInfos[i].tmdId == '' ? false : true
                       }
                       tableData.value = res.ddUserInfos
-                      loading.value = false
+                      //   loading.value = false
                   })
             // const proxys = proxy
             // let valname = val

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

@@ -108,7 +108,7 @@
                                 <el-input v-model="nowPitchdata.name"></el-input>
                             </el-form-item>
                             <el-form-item :label="$t(`schoolManages.basicSet.badge`)+':'" class="school-form-badge">
-                                <el-upload class="upload-demo" :headers="uploadHeader" action="/blob/upload-public" :before-upload="changeBadge" :on-success="success" :on-error="handleUpdErr">
+                                <el-upload class="upload-demo-redact" :headers="uploadHeader" action="/blob/upload-public" :before-upload="changeBadge" :on-success="success" :on-error="handleUpdErr">
                                     <el-image style="width: 100%; height:125px" :src="nowPitchdata.picture" fit="contain"></el-image>
                                     <div class="changebadge">
                                         <el-button>{{$t(`schoolManages.basicSet.badgeChange`)}}</el-button>
@@ -471,7 +471,7 @@ export default {
             proxy.$api.updateSchoolinfo(updateForm).then((res) => {
                 console.log(res, '修改学校的返回')
                 res.state === 200
-                    ? (schoolJoinarea(), schoolClose(), ElMessage.success(proxy.$t(`commonMsg.schoolUpdateSuccess`)), updateSuccess())
+                    ? (ElMessage.success(proxy.$t(`commonMsg.schoolUpdateSuccess`), schoolJoinarea(), schoolClose()), updateSuccess())
                     : ElMessage.error(proxy.$t(`commonMsg.schoolUpdateError`))
             })
         }
@@ -635,7 +635,7 @@ export default {
     margin: 0 auto;
     padding: 1%;
 }
-.upload-demo {
+.upload-demo-redact {
     width: 100%;
     height: 125px;
 }
@@ -925,7 +925,7 @@ export default {
 .backbtn .changebtn {
     padding: 8px 15px;
 }
-.upload-demo .el-upload {
+.upload-demo-redact .el-upload {
     width: 100%;
     height: 125px;
 }

+ 3 - 3
TEAMModelBI/ClientApp/src/view/teachermanage/traitmanage.vue

@@ -547,7 +547,7 @@ export default {
             await proxy.$api.getAbilityDeatils(datas).then(async (res) => {
                 resultData = res.abilityTaskTreeNodes.length
                 console.log(res, '查询章节返回')
-                ;(res.state === 200) !== 0 ? await conductTree(res.abilityTaskTreeNodes) : ElMessage.error(proxy.$t(`commonMsg.chapterApiError`))
+                ;(res.state === 200) !== 0 ? await conductTree(res.abilityTaskTreeNodes) : ElMessage.error(proxy.$t(`commonMsg.treeHint.chapterApiError`))
             })
             return resultData
         }
@@ -588,7 +588,7 @@ export default {
                     let datas = { standard: nowPitchAbility.standard, id: nowPitchAbility.id, tmdId: useris.tmdId, tmdName: useris.tmdName }
                     proxy.$api.delAbility(datas).then((res) => {
                         console.log(res, '删除的返回')
-                        res.state === 204 ? ElMessage.success(proxy.$t(`commonMsg.deleteAbilitySuccess`)) : ElMessage.error(proxy.$t(`commonMsg.deleteAbilityError`))
+                        res.state === 204 ? ElMessage.success(proxy.$t(`commonMsg.treeHint.deleteAbilitySuccess`)) : ElMessage.error(proxy.$t(`commonMsg.treeHint.deleteAbilityError`))
                         pitch(nowPitchAbility)
                     })
                 })
@@ -659,7 +659,7 @@ export default {
             }
             proxy.$api.saveAbility(datas).then((res) => {
                 console.log(res, '修改成功的返回')
-                res.state === 200 ? (ElMessage.success(proxy.$t(`commonMsg.updateSuccess`)), pitch(res.currencys[0])) : ElMessage.error(proxy.$t(`commonMsg.updateError`))
+                res.state === 200 ? (ElMessage.success(proxy.$t(`commonMsg.treeHint.updateSuccess`)), pitch(res.currencys[0])) : ElMessage.error(proxy.$t(`commonMsg.treeHint.updateError`))
                 idBtnLoading.value = false
             })
         }

+ 46 - 44
TEAMModelOS.FunctionV4/ServiceBus/ActiveTaskTopic.cs

@@ -961,9 +961,39 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                 msgs.Add(update);
                                 break;
                             //更新 基础统计信息
-                            //case "up-base":
-                               
-                            //    break;
+                            case "up-base":
+                                //如果有更新 则去读取/{_lessonId}/IES/base.json
+                                try
+                                {
+                                    BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/{_lessonId}/IES/base.json").DownloadContentAsync();
+                                    LessonBase lessonBase = baseblobDownload.Content.ToObjectFromJson<LessonBase>();
+                                    if (lessonBase != null)
+                                    {
+                                        lessonRecord.attendCount = lessonRecord.attendCount;
+                                        lessonRecord.clientCount = lessonRecord.clientCount;
+                                        lessonRecord.attendRate = lessonRecord.attendRate;
+                                        lessonRecord.groupCount = lessonRecord.groupCount;
+                                        lessonRecord.collateTaskCount = lessonRecord.collateTaskCount;
+                                        lessonRecord.collateCount = lessonRecord.collateCount;
+                                        lessonRecord.pushCount = lessonRecord.pushCount;
+                                        lessonRecord.totalPoint = lessonRecord.totalPoint;
+                                        lessonRecord.examQuizCount = lessonRecord.examQuizCount;
+                                        lessonRecord.interactionCount = lessonRecord.interactionCount;
+                                        lessonRecord.examPointRate = lessonRecord.examPointRate;
+                                        lessonRecord.clientInteractionCount = lessonRecord.clientInteractionCount;
+                                        lessonRecord.clientInteractionAverge = lessonRecord.clientInteractionAverge;
+                                    }
+                                    msgs.Add(update);
+                                }
+                                catch (RequestFailedException ex) when (ex.Status == 404)
+                                {
+                                    msgs.Add(new LessonUpdate { grant_type = "up-base-404" });
+                                }
+                                catch (Exception ex)
+                                {
+                                    await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}课程读取base.json,{_lessonId}\n{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
+                                }
+                                break;
 
                             //更新 时间线
                             case "up-TimeLine":
@@ -977,23 +1007,25 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                                 //var activityInfos = ActivityInfoblobDownload.Content.ToObjectFromJson<List<LessonActivityInfo>>();
                                 msgs.Add(update);
                                 break;
-                            //case "up-baseinfo":
-                            //    if (updates.Count > 1)
-                            //    {
-                            //        isReplace = true;
-                            //    }
-                            //    else {
-                            //        isReplace = false;
-                            //    }
-                            //    msgs.Add(update);
-                            //    break;
+                                ///更新基础信息,名称科目,年级,分类等。
+                            case "up-baseinfo":
+                                if (updates.Count > 1)
+                                {
+                                    isReplace = true;
+                                }
+                                else
+                                {
+                                    isReplace = false;
+                                }
+                                msgs.Add(update);
+                                break;
                             case "delete":
                                 try
                                 {
                                     await client.GetContainer(Constant.TEAMModelOS, tbname).DeleteItemAsync<LessonRecord>(lessonId, new PartitionKey(code));
                                     msgs.Add(update);
                                 }
-                                catch (CosmosException ex)
+                                catch (CosmosException)
                                 {
                                     msgs.Add(update);
                                 }
@@ -1092,36 +1124,6 @@ namespace TEAMModelOS.FunctionV4.ServiceBus
                     }
                     //如果被删除则不能再被更新
                     if (isReplace) {
-                        //如果有更新 则去读取/{_lessonId}/IES/base.json
-                        try
-                        {
-                            BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient(blobname).GetBlobClient($"/{_lessonId}/IES/base.json").DownloadContentAsync();
-                            LessonBase lessonBase = baseblobDownload.Content.ToObjectFromJson<LessonBase>();
-                            if (lessonBase != null)
-                            {
-                                lessonRecord.attendCount = lessonRecord.attendCount;
-                                lessonRecord.clientCount = lessonRecord.clientCount;
-                                lessonRecord.attendRate = lessonRecord.attendRate;
-                                lessonRecord.groupCount = lessonRecord.groupCount;
-                                lessonRecord.collateTaskCount = lessonRecord.collateTaskCount;
-                                lessonRecord.collateCount = lessonRecord.collateCount;
-                                lessonRecord.pushCount = lessonRecord.pushCount;
-                                lessonRecord.totalPoint = lessonRecord.totalPoint;
-                                lessonRecord.examQuizCount = lessonRecord.examQuizCount;
-                                lessonRecord.interactionCount = lessonRecord.interactionCount;
-                                lessonRecord.examPointRate = lessonRecord.examPointRate;
-                                lessonRecord.clientInteractionCount = lessonRecord.clientInteractionCount;
-                                lessonRecord.clientInteractionAverge = lessonRecord.clientInteractionAverge;
-                            }
-                            msgs.Add(new LessonUpdate { grant_type = "up-base" });
-                        }
-                        catch (RequestFailedException ex) when (ex.Status == 404)
-                        {
-                            msgs.Add(new LessonUpdate { grant_type = "up-base-404" });
-                        }
-                        catch (Exception ex) {
-                            await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}课程读取base.json,{_lessonId}\n{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
-                        }
                         await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, tbname).ReplaceItemAsync<LessonRecord>(lessonRecord, lessonId, new PartitionKey(code));
                     }
                     //计算课堂更新前后的差值

+ 3 - 3
TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj

@@ -5,9 +5,9 @@
 		<OutputType>Exe</OutputType>
 		<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
 		<SignAssembly>true</SignAssembly>
-		<AssemblyVersion>5.2203.16.1</AssemblyVersion>
-		<FileVersion>5.2203.16.1</FileVersion>
-		<Version>5.2203.16</Version>
+		<AssemblyVersion>5.2203.17.1</AssemblyVersion>
+		<FileVersion>5.2203.17.1</FileVersion>
+		<Version>5.2203.17</Version>
 		<PackageId>TEAMModelOS.FunctionV4</PackageId>
 		<Authors>teammodel</Authors>
 		<Company>醍摩豆(成都)信息技术有限公司</Company>

+ 75 - 164
TEAMModelOS.SDK/Models/Cosmos/Common/LessonRecord.cs

@@ -170,51 +170,12 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public int clientInteractionAverge { get; set; } = 0;
     }
-
-    public class LessonActivityInfo
-    {
-        /// <summary>
-        /// 时间点
-        /// </summary>
-        public List<LessonTC> count { get; set; } = new List<LessonTC>();
-        /// <summary>
-        /// 事件类型
-        /// </summary>
-        public string @event { get; set; }
-        /// <summary>
-        /// 页面id
-        /// </summary>
-        public string pgId { get; set; }
-    }
-    public class LessonStudent
-    {
-        public string id { get; set; }
-        public string name { get; set; }
-        public string type { get; set; }
-        public string code { get; set; }
-        public string picture { get; set; }
-        public string irs { get; set; }
-    }
     public class LessonTC
     {
         public string t { get; set; }
         public double c { get; set; }
     }
-    public class LessonTimeLine
-    {
-        /// <summary>
-        /// 时间点
-        /// </summary>
-        public double time { get; set; }
-        /// <summary>
-        /// 事件类型
-        /// </summary>
-        public string @event { get; set; }
-        /// <summary>
-        /// 页面id
-        /// </summary>
-        public string pgId { get; set; }
-    }
+    
     public class LessonUpdate
     {
         public string grant_type { get; set; }
@@ -290,66 +251,56 @@ namespace TEAMModelOS.SDK.Models
         /// 
         /// </summary>
         public string endTime { get; set; }
+         
+
         /// <summary>
-        /// 
-        /// </summary>
-        public int attendCount { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public int clientCount { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public double attendRate { get; set; }
-        /// <summary>
-        /// 
+        /// 总人数
         /// </summary>
-        public int groupCount { get; set; }
+        public int clientCount { get; set; } = 0;
         /// <summary>
-        /// 
+        ///出席率
         /// </summary>
-        public double totalPoint { get; set; }
+        public double attendRate { get; set; } = 0;
         /// <summary>
-        /// 
+        /// 小组数
         /// </summary>
-        public double totalInteractPoint { get; set; }
+        public int groupCount { get; set; } = 0;
         /// <summary>
-        /// 
+        /// 任务总数,作品收集任务数
         /// </summary>
-        public int collateTaskCount { get; set; }
+        public int collateTaskCount { get; set; } = 0;
         /// <summary>
-        /// 
+        /// 作品总数
         /// </summary>
-        public int collateCount { get; set; }
+        public int collateCount { get; set; } = 0;
         /// <summary>
-        /// 
+        /// 推送总数(页面,资源,讯息,差异化)
         /// </summary>
-        public int pushCount { get; set; }
+        public int pushCount { get; set; } = 0;
         /// <summary>
-        /// 
+        /// 总计分
         /// </summary>
-        public int examCount { get; set; }
+        public double totalPoint { get; set; } = 0;
         /// <summary>
-        /// 
+        /// 测验总题数
         /// </summary>
-        public int examQuizCount { get; set; }
+        public int examQuizCount { get; set; } = 0;
         /// <summary>
-        /// 
+        /// 互动题数
         /// </summary>
-        public double examPointRate { get; set; }
+        public int interactionCount { get; set; } = 0;
         /// <summary>
-        /// 
+        /// 测验得分率
         /// </summary>
-        public int interactionCount { get; set; }
+        public double examPointRate { get; set; } = 0;
         /// <summary>
-        /// 
+        /// 学生互动总数
         /// </summary>
-        public int clientInteractionCount { get; set; }
+        public int clientInteractionCount { get; set; } = 0;
         /// <summary>
-        /// 
+        /// 学生互动率
         /// </summary>
-        public double clientInteractionAverge { get; set; }
+        public int clientInteractionAverge { get; set; } = 0;
     }
 
     public class QuizSummaryList
@@ -434,100 +385,17 @@ namespace TEAMModelOS.SDK.Models
         /// 
         /// </summary>
         public List<ClientSummaryList> clientSummaryList { get; set; }
-        /// <summary>
-        /// 测试新版名单222-罗老师 小课堂
-        /// </summary>
-        public string activityName { get; set; }
-        /// <summary>
-        /// 罗老师
-        /// </summary>
-        public string hostName { get; set; }
-        /// <summary>
-        /// 全客观题
-        /// </summary>
-        public string meterialName { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public string date { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public string startTime { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public string endTime { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public int attendCount { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public int clientCount { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public double attendRate { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public int groupCount { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public double totalPoint { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public double totalInteractPoint { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public int collateTaskCount { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public int collateCount { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public int pushCount { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public int examCount { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public int examQuizCount { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public double examPointRate { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public int interactionCount { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public int clientInteractionCount { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        public double clientInteractionAverge { get; set; }
+        
     }
 
     public class StudentItem
     {
         /// <summary>
-        /// 
+        /// 学生id
         /// </summary>
         public string id { get; set; }
         /// <summary>
-        /// 
+        /// 座号
         /// </summary>
         public int seatID { get; set; }
         /// <summary>
@@ -535,10 +403,53 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public string name { get; set; }
         /// <summary>
-        /// 
+        /// 学生类型
         /// </summary>
         public int type { get; set; }
+        /// <summary>
+        /// 头像
+        /// </summary>
+        public string picture { get; set; }
     }
 
-     
+    //public class LessonActivityInfo
+    //{
+    //    /// <summary>
+    //    /// 时间点
+    //    /// </summary>
+    //    public List<LessonTC> count { get; set; } = new List<LessonTC>();
+    //    /// <summary>
+    //    /// 事件类型
+    //    /// </summary>
+    //    public string @event { get; set; }
+    //    /// <summary>
+    //    /// 页面id
+    //    /// </summary>
+    //    public string pgId { get; set; }
+    //}
+    //public class LessonStudent
+    //{
+    //    public string id { get; set; }
+    //    public string name { get; set; }
+    //    public string type { get; set; }
+    //    public string code { get; set; }
+    //    public string picture { get; set; }
+    //    public string irs { get; set; }
+    //}
+
+    //public class LessonTimeLine
+    //{
+    //    /// <summary>
+    //    /// 时间点
+    //    /// </summary>
+    //    public double time { get; set; }
+    //    /// <summary>
+    //    /// 事件类型
+    //    /// </summary>
+    //    public string @event { get; set; }
+    //    /// <summary>
+    //    /// 页面id
+    //    /// </summary>
+    //    public string pgId { get; set; }
+    //}
 }

+ 6 - 2
TEAMModelOS/ClientApp/src/api/http.js

@@ -16,7 +16,9 @@ const NO_ACCESS_API = [
     '/common/study/sign-in',
     'third/sso/opt-tmdid-bind',
     '/sc/bind',
-    '/oauth2/profile'
+    '/oauth2/profile',
+	'/core/get-short-url',
+	'/core/get-long-url'
 ]
 // 需要携带access_token 不需要携带auth-token
 const NO_AUTH_API = [
@@ -24,7 +26,9 @@ const NO_AUTH_API = [
     '/teacher/init/get-school-info',
     '/grouplist/scan-code-join-list',
 	'/tmduser/init/get-tmduser-info',
-    '/teacher/init/GetUserInfo'
+    '/teacher/init/GetUserInfo',
+	'/core/get-short-url',
+	'/core/get-long-url'
 ]
 // 不进行错误提示白名单
 const NO_WARNING = [

+ 159 - 0
TEAMModelOS/ClientApp/src/common/QrcodeModal.vue

@@ -0,0 +1,159 @@
+<template>
+    <div class="qr-code-wrap" v-show="showQrStatus" @click="showQrStatus = false">
+        <div class="qr-code-info" @click.stop>
+            <p class="qr-code-title">
+                {{config.title}}
+            </p>
+            <div id="qrcode" :class="showQrStatus ? 'animated fadeIn':'animated fadeOut'" ref="qrcode" style="padding:15px 25px 20px 25px;background-color:white;width:330px;margin:auto;">
+            </div>
+            <!-- 自定义内容 -->
+            <slot></slot>
+            <p class="invite-url-text" @click="copyUrl">
+                <Icon type="md-copy" class="copy-link-icon" :title="$t('cusMgt.copyUrl')" />
+                <span style="font-size:14px">{{$t('cusMgt.inviteUrl')}}</span>
+            </p>
+        </div>
+    </div>
+</template>
+<script>
+import QRCode from 'qrcodejs2'
+export default {
+    props: {
+        config: {
+            type: Object,
+            default: () => {
+                return {
+                    title: '标题',
+                    url: '',//不用转短网址,组件内部处理
+                    shareContent: '',//复制链接内容,支持字符串模板,如果包含网址需要处理好短网址
+                }
+            }
+        },
+        value: {
+            type: Boolean,
+            default: false
+        }
+    },
+    model: {
+        prop: "value", //绑定的值,通过父组件传递
+        event: "toggle", //自定义时间名    
+    },
+    data() {
+        return {
+            showQrStatus: false,
+            joinQRcode: undefined
+        }
+    },
+    methods: {
+        async copyUrl() {
+            this.$copyText(this.config.shareContent).then(
+                ok => {
+                    this.$Message.success(this.$t("settings.copyModal1"))
+                },
+                fail => {
+                    this.$Message.error(this.$t("settings.copyModal2"))
+                }
+            )
+        },
+        createQRCode() {
+            this.$nextTick(async () => {
+                // 此时已经渲染完成
+                try {
+                    let shortUrl = await this.$api.getShortUrl(encodeURI(this.config.url))
+                    if (this.joinQRcode == undefined) {
+                        let qrcode = new QRCode('qrcode', {
+                            width: 280, // 设置宽度,单位像素
+                            height: 280, // 设置高度,单位像素
+                            // text: encodeURI(url), // 编码处理
+                            text: shortUrl.result, // 编码处理
+                            correctLevel: QRCode.CorrectLevel.Q //解决编码后网址太长的问题
+                        })
+                        this.joinQRcode = qrcode
+                    } else {
+                        this.joinQRcode.clear()
+                        this.joinQRcode.makeCode(shortUrl.result)
+                    }
+                    let dom = document.getElementById('qrcode')
+                    if (dom) dom.title = ''
+                } catch (e) {
+                    this.$Message.error(this.$t('cusMgt.qrcodeErr'))
+                }
+            })
+        },
+    },
+    created() {
+        console.log(this.showQrStatus)
+    },
+    watch: {
+        config: {
+            deep: true,
+            immediate: true,
+            handler(n, o) {
+                if (n.url) {
+                    this.createQRCode()
+                }
+            }
+        },
+        showQrStatus(newVal, oldVal) {
+            this.$emit("toggle", newVal); //子组件与父组件通讯,告知父组件更新绑定的值
+        },
+        value(n, o) {
+            this.showQrStatus = n
+        }
+    }
+}
+</script>
+<style scoped lang="less">
+.qr-code-wrap {
+    position: fixed;
+    left: 0px;
+    right: 0px;
+    top: 0px;
+    bottom: 0px;
+    background: rgba(103, 103, 103, 0.27);
+    z-index: 99999;
+    display: flex;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}
+.qr-code-info {
+    width: fit-content;
+    height: fit-content;
+    background: white;
+    padding: 30px 40px;
+    margin-top: -150px;
+}
+.qr-code-title {
+    display: block;
+    margin: auto;
+    text-align: center;
+    color: black;
+    font-size: 18px;
+}
+.qr-code-text {
+    display: block;
+    margin: auto;
+    text-align: center;
+    margin-top: -5px;
+    margin-bottom: 5px;
+    color: #0058e7;
+    font-size: 20px;
+}
+.invite-url-text {
+    text-overflow: ellipsis;
+    overflow: hidden;
+    white-space: nowrap;
+    user-select: none;
+    cursor: pointer;
+    color: #2d8cf0;
+    text-align: center;
+}
+.copy-link-icon {
+    // float: right;
+    margin-top: -16px;
+    margin-right: 5px;
+    cursor: pointer;
+    color: #2d8cf0;
+}
+</style>

+ 1 - 1
TEAMModelOS/ClientApp/src/components/evaluation/ExerciseList.vue

@@ -230,7 +230,7 @@
 		methods: {
 			/* 补救资源点击事件 */
 			onRepairLinkClick(link){
-				window.open(link.blobUrl)
+				window.open(/^(http:|https:)/i.test(link.blobUrl) ? link.blobUrl : "http://" + link.blobUrl)
 			},
 			onSelectAll(){
 				let curPageItems = this.exerciseList

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

@@ -423,7 +423,7 @@ export default {
             } else if(item.type === 'doc') {
                 window.open('https://view.officeapps.live.com/op/view.aspx?src=' + escape(url));
             }else if(item.type === 'link') {
-                window.open(url)
+				window.open(/^(http:|https:)/i.test(url) ? url : "http://" + url)
             }
         },
 

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

@@ -532,7 +532,7 @@ export default {
             } else if(item.type === 'image') {
                 this.$hevueImgPreview(url)
             } else if(item.type === 'link') {
-                window.open(url)
+				window.open(/^(http:|https:)/i.test(url) ? url : "http://" + url)
             } else {
                 console.log(1111111111111);
                 this.previewFile = item

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

@@ -855,7 +855,7 @@
                 } else if(item.type === 'image') {
                     this.$hevueImgPreview(url)
                 } else if(item.type === 'link') {
-                    window.open(url)
+					window.open(/^(http:|https:)/i.test(url) ? url : "http://" + url)
                 } else {
                     this.previewFile = item
                     this.previewStatus = true

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

@@ -126,4 +126,39 @@
 }
 .custom-modal-top .ivu-modal{
     top: 60px;
+}
+//修改名称对话框
+.ed-name-modal .ivu-modal-header {
+    border-bottom: none;
+    font-size: 16px;
+    font-weight: bold;
+    padding: 30px 25px 25px 25px;
+
+    .modal-header {
+        display: inline-block;
+        &::before {
+            content: "";
+            display: inline-block;
+            border: 4px solid #80b2c9;
+            border-radius: 50%;
+            margin-right: 10px;
+            margin-bottom: 2px;
+        }
+    }
+}
+.edit-name-content{
+    padding: 0px 30px;
+    .edit-name-label{
+        font-size: 14px;
+        color: #515a6e;
+        margin-bottom: 15px;
+        font-weight: 700;
+    }
+    .confirm-btn{
+        background: #70B1E7;
+        color: white;
+        margin: 40px 0px 45px 0px;
+        height: 40px;
+        border: none;
+    }
 }

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

@@ -147,6 +147,7 @@ export default {
     listSchoolTips2:'學校學生,個人名單不能添加跨校學生。',
     listSchoolTips3:'其他',
     qrcodeErr:'二維碼生成失敗',
+    edRdName:'修改課堂記錄名稱',
 
     //ManageClass.vue
     stuMgt: 'Student Management',

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

@@ -147,6 +147,7 @@ export default {
     listSchoolTips2:'学校学生,个人名单不能添加跨校学生。',
     listSchoolTips3:'其他',
     qrcodeErr:'二维码生成失败',
+    edRdName:'修改课堂记录名称',
 
     //ManageClass.vue
     stuMgt:'学生管理',

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

@@ -1,4 +1,6 @@
 export default{
+	receivedSuc:'接收成功,可前往IES5-个人课纲进行查看',
+	receiveBtn:'确认接收',
 	noMatchTerm:'无匹配学期',
 	emptyTip:'空目录册别无法进行分享!',
 	chooseChapterTip:'请先选择需要收藏的章节!',

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

@@ -147,6 +147,7 @@ export default {
     listSchoolTips2:'學校學生,個人名單不能添加跨校學生。',
     listSchoolTips3:'其他',
     qrcodeErr:'二維碼生成失敗',
+    edRdName:'修改課堂記錄名稱',
 
     //ManageClass.vue
     stuMgt: '學生管理',

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

@@ -1,4 +1,6 @@
 export default {
+	receivedSuc:'接收成功,可前往IES5-個人課綱進行查看',
+	receiveBtn:'確認接收',
 	noMatchTerm: '無匹配學期',
 	emptyTip: '空目錄冊別無法進行分享!',
 	chooseChapterTip: '請先選擇需要收藏的章節!',

+ 4 - 0
TEAMModelOS/ClientApp/src/router/routes.js

@@ -123,6 +123,10 @@ export const routes = [{
 	path: '/joinclass',
 	component: resolve => require(['@/view/joinclass/JoinClass.vue'], resolve)
 },
+{
+	path: '/shareSyllabus',
+	component: resolve => require(['@/view/shareSyllabus/ShareSyllabus.vue'], resolve)
+},
 //单点登录
 {
 	path: '/sso',

+ 2 - 2
TEAMModelOS/ClientApp/src/utils/editorTools.js

@@ -303,7 +303,7 @@ export default {
 					tpl: '<div class="w-e-up-img-container">\n <div id="' + inputIFrameId +
 						'" class="w-e-up-btn">\n<i class="w-e-icon-upload2"></i>\n</div>\n <div style="display:none;">\n<input id="' +
 						upFileId +
-						'" type="file" accept="video/*"/>\n</div>\n</div>',
+						'" type="file" accept=".mp4,.webm"/>\n</div>\n</div>',
 					// 事件绑定
 					events: [
 						// 插入视频
@@ -423,7 +423,7 @@ export default {
 					tpl: '<div class="w-e-up-img-container">\n <div id="' + inputIFrameId +
 						'" class="w-e-up-btn">\n<i class="w-e-icon-upload2"></i>\n</div>\n <div style="display:none;">\n<input id="' +
 						upFileId +
-						'" type="file" multiple="multiple" accept="audio/*"/>\n</div>\n</div>',
+						'" type="file" multiple="multiple" accept=".mp3,.ogg,.wav"/>\n</div>\n</div>',
 					// 事件绑定
 					events: [
 						// 插入视频

+ 1 - 1
TEAMModelOS/ClientApp/src/view/abilityMgmt/Index.vue

@@ -1826,7 +1826,7 @@
 						this.isPreviewPaper = true
 						break;
 					case 'link':
-						window.open(item.link);
+						window.open(/^(http:|https:)/i.test(item.link) ? item.link : "http://" + item.link)
 						break;
 					case 'other':
 						this.$Message.warning(this.$t('syllabus.noPreview'))

+ 5 - 5
TEAMModelOS/ClientApp/src/view/areatrain/TrainDetail.vue

@@ -892,12 +892,12 @@ export default {
                     let qrcode = new QRCode('fullqrcode', {
                         width: 320, // 设置宽度,单位像素
                         height: 320, // 设置高度,单位像素
-                        text: url // 设置二维码内容或跳转地址
+                        text: shortUrl.result // 设置二维码内容或跳转地址
                     })
                     this.fullQR = qrcode
                 } else {
                     this.fullQR.clear()
-                    this.fullQR.makeCode(url)
+                    this.fullQR.makeCode(shortUrl.result)
                 }
                 let dom = document.getElementById('fullqrcode')
                 if (dom) dom.title = ''
@@ -908,18 +908,18 @@ export default {
             this.$nextTick(async () => {
                 // 此时已经渲染完成
                 let url = this.handleUrl()
-                let shortUrl = await this.$api.getShortUrl(encodeURI(url)) //暂不替换,等路由处理好了再替换
+                let shortUrl = await this.$api.getShortUrl(encodeURI(url)) 
                 console.log(url)
                 if (!this.signQRcode) {
                     let qrcode = new QRCode('sign-qr-code', {
                         width: 150, // 设置宽度,单位像素
                         height: 150, // 设置高度,单位像素
-                        text: url // 设置二维码内容或跳转地址
+                        text: shortUrl.result // 设置二维码内容或跳转地址
                     })
                     this.signQRcode = qrcode
                 } else {
                     this.signQRcode.clear()
-                    this.signQRcode.makeCode(url)
+                    this.signQRcode.makeCode(shortUrl.result)
                 }
                 let dom = document.getElementById('qrcode')
                 if (dom) dom.title = ''

+ 1 - 1
TEAMModelOS/ClientApp/src/view/auth/Product.vue

@@ -156,7 +156,7 @@ export default {
                 let lang = localStorage.getItem('local') || 'zh-cn'
                 for (let key in urls) {
                     if (lang.includes(key)) {
-                        window.open(urls[key])
+						window.open(/^(http:|https:)/i.test(urls[key]) ? urls[key] : "http://" + urls[key])
                         break
                     }
                 }

+ 1 - 1
TEAMModelOS/ClientApp/src/view/evaluation/bank/ExerciseList.vue

@@ -387,7 +387,7 @@
 			
 			/* 补救资源点击事件 */
 			onRepairLinkClick(link){
-				window.open(link.blobUrl)
+				window.open(/^(http:|https:)/i.test(link.blobUrl) ? link.blobUrl : "http://" + link.blobUrl)
 			},
 			
 			/* 升序降序操作 */

+ 162 - 16
TEAMModelOS/ClientApp/src/view/evaluation/bank/PaperDownload.vue

@@ -10,11 +10,11 @@
 				</div>
 				<div class="base-bg">
 					<div class="base-bg-page" v-for="(page,pageIndex) in pageArr" :key="pageIndex" :style="{ borderBottom: isDownloading ? 'none' : '1px solid #ccc' }">
-						<div class="dp-line" v-show="settingArr[0]">
+						<div class="dp-line" v-show="settingArr[0] && (printMode === 'A3' ? pageIndex % 2 === 0 : true)">
 							<img src="@/assets/image/peal_line.png">
 						</div>
 						<p class="page-num">
-							第 {{ pageIndex + 1 }} 页 / 共 {{ pageArr.length }} 页
+							<!-- 第 {{ pageIndex + 1 }} 页 / 共 {{ pageArr.length }} 页 -->
 						</p>
 					</div>
 				</div>
@@ -99,12 +99,28 @@
 	</div>
 		<div class="dp-right">
 			<Button type="primary" @click="goBack">返回上级</Button>
-			<Button type="success" @click="onDownloadPaper">下载试卷</Button>
+			<Button type="success" @click="pdfModal = true">下载试卷</Button>
 			<div>
 				<p class="dp-right-title">试卷设置</p>
 				<Checkbox v-for="(item,index) in settingOptions" :key="index" v-model="settingArr[index]" @on-change="onSettingChange(index)">&nbsp;{{ item }}</Checkbox>
 			</div>
 		</div>
+		
+		<Modal v-model="pdfModal" class-name="add-type-modal pdf-modal" width="650" :title="$t('answerSheet.print')"
+			@on-ok="onDownloadPaper">
+			<div class="pdf-wrap">
+				<div style="display: flex;flex-direction: column;align-items: center;">
+					<div :class="['a4', printMode ==='A4' ? 'mode-active' : '']" @click="printMode ='A4'">A4</div>
+					<p style="margin-top: 10px;">{{ $t('answerSheet.printA4') }}</p>
+					<p style="margin-top: 10px;font-size: 12px;">{{ $t('answerSheet.singleColumn') }} (210mm * 297mm)</p>
+				</div>
+				<div style="display: flex;flex-direction: column;align-items: center;">
+					<div :class="['a3', printMode ==='A3' ? 'mode-active' : '']" @click="printMode ='A3'">A3</div>
+					<p style="margin-top: 10px;">{{ $t('answerSheet.printA3') }}</p>
+					<p style="margin-top: 10px;font-size: 12px;">{{ $t('answerSheet.doubleColumn') }} (420mm * 297mm)</p>
+				</div>
+			</div>
+		</Modal>
 	</div>
 </template>
 <script>
@@ -120,6 +136,8 @@
 		},
 		data() {
 			return {
+				pdfModal:false,
+				printMode:'A4',
 				scrollTop:0,
 				isDownloading:false,
 				pageArr:[0,1],
@@ -194,18 +212,117 @@
 							let pageHeight = contentWidth / 592.28 * 841.89
 							let leftHeight = contentHeight
 							let position = 0
-							const imgWidth = 595.28
-							let imgHeight = 592.28 / contentWidth * contentHeight
-							let PDF = new JsPDF('', 'pt', 'a4')
-							if (leftHeight < pageHeight) {
-								PDF.addImage(pageData, 'JPEG', 0, 10, imgWidth, imgHeight)
-							} else {
-								while (leftHeight > 0) {
-									PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
-									leftHeight -= pageHeight
-									position -= 841.89
-									if (leftHeight > 0) {
-										PDF.addPage()
+							let mode = that.printMode
+							console.log(mode);
+							let PDF = null
+							const a4HeightPx = 1168
+							const a4WidthPx = 826
+							const a4Height = 297
+							const a4Width = 210
+							let imgWidth = a4Width
+							let imgHeight = a4Width / contentWidth * contentHeight
+							let mm2px = that.$tools.getOneMmsPx()
+							let xMarginMM = 15 / mm2px - 0.2
+							let yMarginMM = 40 / mm2px
+							
+							/* 分割长图 */
+							function segmentationImage(img, width, height) {
+							  let canvas = document.createElement("canvas");
+								canvas.width = width;
+								canvas.height = height;
+							  let ctx = canvas.getContext("2d");
+							  let imgList = [];
+							  let cropCount = Math.ceil(img.height / height);
+							  for(let num = 0; num < cropCount; num++) {
+								ctx.clearRect(0,0,canvas.width,canvas.height);
+								ctx.drawImage(img, 0, num * height, width, height, 0, 0, width, height);
+								imgList.push(canvas.toDataURL());
+							  }
+							  return imgList
+							}
+							/* 用JSPDF绘制每一页的外框页码和答题卡编号 */
+							function pdfDrawInfo(pageNo){
+								let curPage = mode === 'A4' ? pageNo : pageNo / 2
+								// 页码二进制框
+								let i = curPage.toString(2)
+
+								PDF.setFont('Times New Roman')
+								if(mode === 'A4'){
+									// 页码
+									PDF.text(`${curPage} / ${totalPage}`, a4Width / 2 - 5, a4Height - 4,'center')
+								}else{
+									// 页码
+									PDF.text(`${curPage} / ${ totalPage }`, a4Width, a4Height - 4,'center')
+								}
+								
+							}
+							// 获取分割的图片数量
+							let cropCount = that.pageArr.length;
+							if(cropCount === 0) return
+							let totalPage = mode === 'A4' ? cropCount : ( (cropCount % 2 === 0) ? (cropCount / 2) : ((cropCount + 1) / 2) )
+							if(mode === 'A4'){
+								PDF = new JsPDF({
+									orientation: 'p',
+									unit: 'mm',
+									format: 'a4',
+									putOnlyUsedFonts: true
+								})
+								PDF.setFont('Times New Roman')
+								PDF.setFontSize(10);
+								let curPage = 1
+								// 如果是一页的情况
+								if (leftHeight <= pageHeight) {
+									PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth,
+										imgHeight)
+										pdfDrawInfo(1)
+								} else {
+									// 如果超出则多页
+									while (leftHeight > 0) {
+										PDF.addImage(pageData, 'JPEG', 0, position,
+											imgWidth, imgHeight)
+										leftHeight -= pageHeight
+										position -= a4Height
+										pdfDrawInfo(curPage)
+										if (leftHeight > 0) {
+											PDF.addPage()
+										}
+										curPage++
+									}
+								}
+							}else{
+								/* 渲染A3纸张 */
+								PDF = new JsPDF({
+									orientation: 'l',
+									unit: 'mm',
+									format: 'a3',
+									putOnlyUsedFonts: true
+								})
+								PDF.setFont('Times New Roman')
+								PDF.setFontSize(10);
+								let pageImgArr = segmentationImage(img, a4WidthPx, a4HeightPx);
+								let curPage = 1
+								// 如果是一页的情况
+								if (leftHeight <= pageHeight) {
+									PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth,imgHeight)
+									pdfDrawInfo(2)
+								} else {
+									// 如果超出则多页
+									while (leftHeight > 0) {
+										if(curPage % 2 === 0){
+											PDF.addImage(pageImgArr[curPage - 1], 'JPEG', a4Width, 0, a4Width, a4Height)
+											leftHeight -= pageHeight
+											pdfDrawInfo(curPage)
+											if (leftHeight > 0) {
+												PDF.addPage()
+											}
+										}else{
+											PDF.addImage(pageImgArr[curPage - 1], 'JPEG', 0, 0,a4Width, a4Height)
+											leftHeight -= pageHeight
+											if (leftHeight <= 0) {
+												pdfDrawInfo(totalPage * 2)
+											}
+										}
+										curPage++
 									}
 								}
 							}
@@ -254,7 +371,7 @@
 						// 单页面高度
 						let pageHeight = 1168
 						// 每个页面的边距
-						let pageMargin = 40
+						let pageMargin = 50
 						// 计算当前DOM距离当前页面的Y值 70是减去header+margin距离 再减去已经超出的页面距离 再加上跨页造成的下移距离
 						let domY = (dom.getBoundingClientRect().top + this.scrollTop - 70) - (pageHeight * curPage) + extraMarTop
 						let domH = dom.getBoundingClientRect().height
@@ -327,3 +444,32 @@
 <style lang="less" scoped>
 	@import "./PaperDownload.less";
 </style>
+<style lang="less">
+	.pdf-modal {
+		.pdf-wrap {
+			display: flex;
+			align-items: center;
+			justify-content: space-around;
+	
+			.a4 {
+				padding: 60px 40px;
+				border: 2px solid #c0c0c0;
+				border-radius: 4px;
+				cursor: pointer;
+			}
+	
+			.a3 {
+				padding: 60px 80px;
+				border: 2px solid #c0c0c0;
+				border-radius: 4px;
+				cursor: pointer;
+			}
+	
+			.mode-active {
+				background: #53c6ff;
+				color: #fff;
+				font-size: 14px;
+			}
+		}
+	}
+</style>

+ 1 - 1
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseChild.vue

@@ -239,7 +239,7 @@
 			},
 			/* 补救资源点击事件 */
 			onRepairLinkClick(link){
-				window.open(link.blobUrl)
+				window.open(/^(http:|https:)/i.test(link.blobUrl) ? link.blobUrl : "http://" + link.blobUrl)
 			},
 			onEditChildFinish(item) {
 				console.log(item)

+ 1 - 1
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseExerciseList.vue

@@ -448,7 +448,7 @@
 			},
 			/* 补救资源点击事件 */
 			onRepairLinkClick(link){
-				window.open(link.blobUrl)
+				window.open(/^(http:|https:)/i.test(link.blobUrl) ? link.blobUrl : "http://" + link.blobUrl)
 			},
 			/* 更换题号模板 */
 			onConfirmOrderTemp(index){

+ 1 - 1
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseRepair.vue

@@ -243,7 +243,7 @@
 				}else if(item.type === 'image'){
 					this.$hevueImgPreview(url)
 				}else if(item.type === 'link'){
-					window.open(url)
+					window.open(/^(http:|https:)/i.test(url) ? url : "http://" + url)
 				}else{
 					this.previewFile = item
 					this.previewStatus = true

+ 2 - 1
TEAMModelOS/ClientApp/src/view/homepage/HomePage.vue

@@ -319,7 +319,8 @@ export default {
     },
     methods: {
         openPlatform(index) {
-            window.open(this.platformList[index].url)
+			let url = this.platformList[index].url
+			window.open(/^(http:|https:)/i.test(url) ? url : "http://" + url)
         },
         //查看课堂记录统计数据
         getTeacherRecordData() {

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

@@ -935,7 +935,7 @@ export default {
             }
             // 超链接可能没有hash,就需要重新加密
             if(item.type === "link") {
-                window.open(item.link)
+				window.open(/^(http:|https:)/i.test(item.link) ? item.link : "http://" + item.link)
                 item.hash = item.hash ? item.hash : this.$tools.getStringMd5(item.link)
                 // item.size = 0
             } else {

+ 34 - 20
TEAMModelOS/ClientApp/src/view/learnactivity/MgtPrivEva.vue

@@ -44,7 +44,7 @@
                 </div>
                 <div class="evaluation-list-main">
                     <vuescroll>
-                        <div v-for="(item,index) in evaListShow" @click="selectEvaluation(index)" :class="['evaluation-item','block-bg',index == curEvaIndex ? 'block-bg-active':'']" :key="index">
+                        <div v-for="(item,index) in evaListShow" @click.capture="selectEvaluation(index)" :class="['evaluation-item','block-bg',index == curEvaIndex ? 'block-bg-active':'']" :key="index">
                             <p class="evaluation-name">
                                 {{item.name}}
                                 <!-- 修改评测名称 -->
@@ -127,18 +127,33 @@
                         <strong style="color:#2d8cf0">{{getSchoolName(evaListShow[curEvaIndex].school)}}</strong>
                         {{$t('learnActivity.mgtScEv.tst2')}}
                     </p>
-                    <!-- <p class="toggle-school-btn">
-                        {{$t('learnActivity.mgtScEv.tst3')}}
-                    </p> -->
                 </div>
             </div>
         </Split>
-        <Modal v-model="editTimeStatus" :title="$t('learnActivity.mgtScEv.editEndTime')" @on-ok="confirmEditEndtime" :loading="modalLoading">
-            <DatePicker v-model="editTime" :options="dateOpt1" type="datetime" @on-change="handleTime" format="yyyy-MM-dd HH:mm" :placeholder="$t('learnActivity.mgtScEv.endTimeHolder')" style="width: 100%"></DatePicker>
+        <Modal v-model="editTimeStatus" footer-hide className="ed-name-modal" @on-ok="confirmEditEndtime">
+            <div slot="header" class="modal-header">
+                {{$t('learnActivity.mgtScEv.editEndTime')}}
+            </div>
+            <div class="edit-name-content">
+                <p class="edit-name-label">
+                    {{$t('cusMgt.listName')}}
+                </p>
+                <DatePicker v-model="editTime" :options="dateOpt1" type="datetime" @on-change="handleTime" format="yyyy-MM-dd HH:mm" :placeholder="$t('learnActivity.mgtScEv.endTimeHolder')" style="width: 100%"></DatePicker>
+                <Button :loading="btnLoading" @click="confirmEditEndtime" long type="primary" class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
+            </div>
         </Modal>
         <!-- 修改评测名称 -->
-        <Modal v-model="editNameStatus" :title="$t('learnActivity.mgtScEv.edName')" @on-ok="confirmEditName" :loading="modalLoading">
-            <Input v-model="editName" :placeholder="$t('learnActivity.mgtScEv.edNameHolder')" />
+        <Modal v-model="editNameStatus" footer-hide className="ed-name-modal" @on-ok="confirmEditName" :loading="modalLoading">
+            <div slot="header" class="modal-header">
+                {{$t('learnActivity.mgtScEv.edName')}}
+            </div>
+            <div class="edit-name-content">
+                <p class="edit-name-label">
+                    {{$t('cusMgt.listName')}}
+                </p>
+                <Input v-model="editName" :placeholder="$t('learnActivity.mgtScEv.edNameHolder')" />
+                <Button :loading="btnLoading" @click="confirmEditName" long type="primary" class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
+            </div>
         </Modal>
         <div class="qr-code-wrap" v-show="showQrStatus" @click="showQrStatus = false">
             <div class="qr-code-info" @click.stop>
@@ -167,6 +182,7 @@ export default {
     inject: ['reload'],
     data() {
         return {
+            btnLoading:false,
             shareUrl: '',
             showQrStatus: false,
             modalLoading: true,
@@ -256,12 +272,13 @@ export default {
                 })
             }
         },
-        copyUrl() {
+        async copyUrl() {
             let evName = this.evaListShow[this.curEvaIndex].name
             let evType = this.getModeLabel(this.evaListShow[this.curEvaIndex].source)
             let soc = this.evaListShow[this.curEvaIndex].owner === 'school' ? this.$t('learnActivity.mgtScEv.shareText4') : this.$t('learnActivity.mgtScEv.shareText5')
             let socName = this.evaListShow[this.curEvaIndex].subjects.map(item => item.name).join('、')
-            let shareText = `${this.$t('learnActivity.mgtScEv.shareText1')}\n\n${this.$t('learnActivity.mgtScEv.shareText2')}${evName}\n${this.$t('learnActivity.mgtScEv.shareText3')}${evType}\n${soc}${socName}\n\n${this.$t('learnActivity.mgtScEv.shareText6')}\n${encodeURI(this.shareUrl)}\n\n${this.$t('learnActivity.mgtScEv.shareText7')}\nURL:https://${window.location.host}/login/student`
+            let shortUrl = await this.$api.getShortUrl(encodeURI(this.shareUrl)) //暂不替换,等路由处理好了再替换
+            let shareText = `${this.$t('learnActivity.mgtScEv.shareText1')}\n\n${this.$t('learnActivity.mgtScEv.shareText2')}${evName}\n${this.$t('learnActivity.mgtScEv.shareText3')}${evType}\n${soc}${socName}\n\n${this.$t('learnActivity.mgtScEv.shareText6')}\n${shortUrl.result}\n\n${this.$t('learnActivity.mgtScEv.shareText7')}\nURL:https://${window.location.host}/login/student`
             this.$copyText(shareText).then(
                 ok => {
                     this.$Message.success(this.$t("settings.copyModal1"))
@@ -280,13 +297,13 @@ export default {
                     let qrcode = new QRCode('qrcode', {
                         width: 280, // 设置宽度,单位像素
                         height: 280, // 设置高度,单位像素
-                        text: encodeURI(this.shareUrl), // 编码处理
+                        text: shortUrl.result, // 编码处理
                         correctLevel: QRCode.CorrectLevel.Q //解决编码后网址太长的问题
                     })
                     this.shareQRcode = qrcode
                 } else {
                     this.shareQRcode.clear()
-                    this.shareQRcode.makeCode(encodeURI(this.shareUrl))
+                    this.shareQRcode.makeCode(shortUrl.result)
                 }
                 let dom = document.getElementById('qrcode')
                 if (dom) dom.title = ''
@@ -308,6 +325,7 @@ export default {
         confirmEditName() {
             if (this.editName) {
                 this.evaListShow[this.curEvaIndex].code = this.evaListShow[this.curEvaIndex].code.replace('Exam-', '')
+                this.btnLoading = true
                 this.$api.learnActivity.updExamEndtime({
                     id: this.evaListShow[this.curEvaIndex].id,
                     code: this.evaListShow[this.curEvaIndex].code,
@@ -326,13 +344,11 @@ export default {
                     }
                 ).finally(() => {
                     this.editNameStatus = false
+                    this.btnLoading = false
                 })
             } else {
                 this.$Message.warning(this.$t('learnActivity.mgtScEv.edNameHolder'))
-                this.modalLoading = false
-                setTimeout(() => {
-                    this.modalLoading = true
-                })
+                this.btnLoading = false
             }
         },
         handleTime(value) {
@@ -344,6 +360,7 @@ export default {
         confirmEditEndtime() {
             if (this.editTime) {
                 this.evaListShow[this.curEvaIndex].code = this.evaListShow[this.curEvaIndex].code.replace('Exam-', '')
+                this.btnLoading = true
                 this.$api.learnActivity.updExamEndtime({
                     id: this.evaListShow[this.curEvaIndex].id,
                     code: this.evaListShow[this.curEvaIndex].code,
@@ -362,13 +379,10 @@ export default {
                     }
                 ).finally(() => {
                     this.editTimeStatus = false
+                    this.btnLoading = false
                 })
             } else {
                 this.$Message.warning(this.$t('learnActivity.mgtScEv.endTimeHolder'))
-                this.modalLoading = false
-                setTimeout(() => {
-                    this.modalLoading = true
-                })
             }
         },
         editEvEndtime(index) {

+ 34 - 10
TEAMModelOS/ClientApp/src/view/learnactivity/MgtSchoolEva.vue

@@ -45,7 +45,7 @@
                 </div>
                 <div class="evaluation-list-main">
                     <vuescroll>
-                        <div v-for="(item,index) in evaListShow" @click="selectEvaluation(index)" :class="['evaluation-item','block-bg',index == curEvaIndex ? 'block-bg-active':'']" :key="index">
+                        <div v-for="(item,index) in evaListShow" @click.capture="selectEvaluation(index)" :class="['evaluation-item','block-bg',index == curEvaIndex ? 'block-bg-active':'']" :key="index">
                             <p class="evaluation-name">
                                 {{item.name}}
                                 <!-- 修改评测名称 -->
@@ -144,12 +144,30 @@
             </div>
         </Split>
         <!-- 修改评测时间 -->
-        <Modal v-model="editTimeStatus" :title="$t('learnActivity.mgtScEv.editEndTime')" @on-ok="confirmEditEndtime" :loading="modalLoading">
-            <DatePicker v-model="editTime" :options="dateOpt1" type="datetime" @on-change="handleTime" format="yyyy-MM-dd HH:mm" :placeholder="$t('learnActivity.mgtScEv.endTimeHolder')" style="width: 100%"></DatePicker>
+        <Modal v-model="editTimeStatus" footer-hide className="ed-name-modal">
+            <div slot="header" class="modal-header">
+                {{$t('learnActivity.mgtScEv.editEndTime')}}
+            </div>
+            <div class="edit-name-content">
+                <p class="edit-name-label">
+                    {{$t('cusMgt.listName')}}
+                </p>
+                <DatePicker v-model="editTime" :options="dateOpt1" type="datetime" @on-change="handleTime" format="yyyy-MM-dd HH:mm" :placeholder="$t('learnActivity.mgtScEv.endTimeHolder')" style="width: 100%"></DatePicker>
+                <Button :loading="btnLoading" @click="confirmEditEndtime" long type="primary" class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
+            </div>
         </Modal>
         <!-- 修改评测名称 -->
-        <Modal v-model="editNameStatus" :title="$t('learnActivity.mgtScEv.edName')" @on-ok="confirmEditName" :loading="modalLoading">
-            <Input v-model="editName" :placeholder="$t('learnActivity.mgtScEv.edNameHolder')" />
+        <Modal v-model="editNameStatus" footer-hide className="ed-name-modal" @on-ok="confirmEditName" :loading="modalLoading">
+            <div slot="header" class="modal-header">
+                {{$t('learnActivity.mgtScEv.edName')}}
+            </div>
+            <div class="edit-name-content">
+                <p class="edit-name-label">
+                    {{$t('cusMgt.listName')}}
+                </p>
+                <Input v-model="editName" :placeholder="$t('learnActivity.mgtScEv.edNameHolder')" />
+                <Button :loading="btnLoading" @click="confirmEditName" long type="primary" class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
+            </div>
         </Modal>
         <div class="qr-code-wrap" v-show="showQrStatus" @click="showQrStatus = false">
             <div class="qr-code-info" @click.stop>
@@ -179,6 +197,7 @@ export default {
     inject: ['reload'],
     data() {
         return {
+            btnLoading: false,
             shareUrl: '',
             showQrStatus: false,
             modalLoading: true,
@@ -248,12 +267,13 @@ export default {
             }
 
         },
-        copyUrl() {
+        async copyUrl() {
             let evName = this.evaListShow[this.curEvaIndex].name
             let evType = this.getModeLabel(this.evaListShow[this.curEvaIndex].source)
             let soc = this.evaListShow[this.curEvaIndex].owner === 'school' ? this.$t('learnActivity.mgtScEv.shareText4') : this.$t('learnActivity.mgtScEv.shareText5')
             let socName = this.evaListShow[this.curEvaIndex].subjects.map(item => item.name).join('、')
-            let shareText = `${this.$t('learnActivity.mgtScEv.shareText1')}\n\n${this.$t('learnActivity.mgtScEv.shareText2')}${evName}\n${this.$t('learnActivity.mgtScEv.shareText3')}${evType}\n${soc}${socName}\n\n${this.$t('learnActivity.mgtScEv.shareText6')}\n${encodeURI(this.shareUrl)}\n\n${this.$t('learnActivity.mgtScEv.shareText7')}\nURL:https://${window.location.host}/login/student`
+            let shortUrl = await this.$api.getShortUrl(encodeURI(this.shareUrl))
+            let shareText = `${this.$t('learnActivity.mgtScEv.shareText1')}\n\n${this.$t('learnActivity.mgtScEv.shareText2')}${evName}\n${this.$t('learnActivity.mgtScEv.shareText3')}${evType}\n${soc}${socName}\n\n${this.$t('learnActivity.mgtScEv.shareText6')}\n${shortUrl.result}\n\n${this.$t('learnActivity.mgtScEv.shareText7')}\nURL:https://${window.location.host}/login/student`
             this.$copyText(shareText).then(
                 ok => {
                     this.$Message.success(this.$t("settings.copyModal1"))
@@ -266,19 +286,19 @@ export default {
         openQrcode() {
             this.$nextTick(async () => {
                 this.shareUrl = `https://${window.location.host}/studentWeb/eventView?aId=${this.evaListShow[this.curEvaIndex].id}`
-                let shortUrl = await this.$api.getShortUrl(encodeURI(this.shareUrl)) //暂不替换,等路由处理好了再替换
+                let shortUrl = await this.$api.getShortUrl(encodeURI(this.shareUrl))
                 // 此时已经渲染完成
                 if (this.shareQRcode == undefined) {
                     let qrcode = new QRCode('qrcode', {
                         width: 280, // 设置宽度,单位像素
                         height: 280, // 设置高度,单位像素
-                        text: encodeURI(this.shareUrl), // 编码处理
+                        text: shortUrl.result, // 编码处理
                         correctLevel: QRCode.CorrectLevel.Q //解决编码后网址太长的问题
                     })
                     this.shareQRcode = qrcode
                 } else {
                     this.shareQRcode.clear()
-                    this.shareQRcode.makeCode(encodeURI(this.shareUrl))
+                    this.shareQRcode.makeCode(shortUrl.result)
                 }
                 let dom = document.getElementById('qrcode')
                 if (dom) dom.title = ''
@@ -294,6 +314,7 @@ export default {
         confirmEditEndtime() {
             if (this.editTime) {
                 this.evaListShow[this.curEvaIndex].code = this.evaListShow[this.curEvaIndex].code.replace('Exam-', '')
+                this.btnLoading = true
                 this.$api.learnActivity.updExamEndtime({
                     id: this.evaListShow[this.curEvaIndex].id,
                     code: this.evaListShow[this.curEvaIndex].code,
@@ -312,6 +333,7 @@ export default {
                     }
                 ).finally(() => {
                     this.editTimeStatus = false
+                    this.btnLoading = false
                 })
             } else {
                 this.$Message.warning(this.$t('learnActivity.mgtScEv.endTimeHolder'))
@@ -328,6 +350,7 @@ export default {
         confirmEditName() {
             if (this.editName) {
                 this.evaListShow[this.curEvaIndex].code = this.evaListShow[this.curEvaIndex].code.replace('Exam-', '')
+                this.btnLoading = true
                 this.$api.learnActivity.updExamEndtime({
                     id: this.evaListShow[this.curEvaIndex].id,
                     code: this.evaListShow[this.curEvaIndex].code,
@@ -346,6 +369,7 @@ export default {
                     }
                 ).finally(() => {
                     this.editNameStatus = false
+                    this.btnLoading = false
                 })
             } else {
                 this.$Message.warning(this.$t('learnActivity.mgtScEv.edNameHolder'))

+ 1 - 1
TEAMModelOS/ClientApp/src/view/login/Index.vue

@@ -459,7 +459,7 @@ export default {
                 let tokenData = jwtDecode(res.id_token)
                 localStorage.setItem("access_token",res.access_token)
                 //token解析出来为字符串,所以需要对比字符串‘false’
-                if (tokenData.isActivate === 'false' && this.$store.state.config.srvAdr == 'China') {
+                if (tokenData.isMobile === 'false' && this.$store.state.config.srvAdr == 'China') {
                     //未启用,前往绑定手机号
                     this.$router.push({
                         path: '/bandphone',

+ 5 - 38
TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.less

@@ -232,19 +232,6 @@
     display: none;
     color: #2d8cf0;
 }
-.qr-code-wrap {
-    position: fixed;
-    left: 0px;
-    right: 0px;
-    top: 0px;
-    bottom: 0px;
-    background: rgba(103, 103, 103, 0.27);
-    z-index: 99999;
-    display:flex;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-}
 .record-name{
     color:var(--primary-text-color);
     font-size:16px;
@@ -377,29 +364,6 @@
     float: right;
     font-size: 12px;
 }
-.qr-code-info{
-    width: fit-content;
-    height: fit-content;
-    background: white;
-    padding: 30px 40px;;
-    margin-top: -150px;
-}
-.invite-url-text{
-    text-overflow: ellipsis;
-    overflow: hidden;
-    white-space: nowrap;
-    user-select: none;
-    cursor: pointer;
-    color: #2d8cf0;
-    text-align: center;
-}
-.copy-link-icon{
-    // float: right;
-    margin-top: -16px;
-    margin-right: 5px;
-    cursor: pointer;
-    color: #2d8cf0;
-}
 .cus-type-item{
     margin-right: 10px !important;
     margin-left: 15px;
@@ -412,12 +376,15 @@
     font-weight: 500;
     margin-right: 20px;
 }
+.set-irs-tips{
+    margin-top: 10px;
+    font-size: 15px;
+}
 .create-list-tips{
     color: #ff9900;
     font-size: 12px;
     line-height: 20px;
     display: inline-block;
-    padding: 0px 20px;
 }
 .system-classroom-table{
     width: 100%;
@@ -498,4 +465,4 @@
 }
 .action-text{
     color: #2d8cf0;
-}
+}

+ 198 - 201
TEAMModelOS/ClientApp/src/view/newcourse/MyCourse.vue

@@ -9,6 +9,7 @@
                     <span v-for="(item,index) in cusType" :key="index" @click="tabClick(item.value)" :class="{ active: item.value == listType }" class="cus-type-item pane">
                         {{item.label}}
                     </span>
+
                     <div style="margin-top:0px;float:right;">
                         <Icon type="md-add" v-show="listType == 'private'" class="add-icon" :title="$t('cusMgt.addCus')" @click="addCusStatus = true" />
                         <Icon type="md-trash" v-show="listType == 'private'" class="add-icon" :title="$t('cusMgt.delCus')" @click="delCourse" />
@@ -152,7 +153,10 @@
                                         <ListItemMeta @click.native="toClassRecoerd(index)" style="cursor: pointer;">
                                             <div slot="avatar" class="record-poster-wrap" :style="{backgroundImage:`url(${item.poster})`}">
                                             </div>
-                                            <p slot="title" class="record-name" style="padding-left:10px">{{item.name}}</p>
+                                            <p slot="title" class="record-name" style="padding-left:10px">
+                                                {{item.name}}
+                                                <Icon type="md-create" class="edit-ev-name" @click.stop="editRecordName(index)" :title="$t('cusMgt.edRdName')" />
+                                            </p>
                                             <div slot="description" style="padding-left:10px;margin-top:10px">
                                                 <!-- 出席率 -->
                                                 <span class="record-info">
@@ -295,50 +299,58 @@
             </vuescroll>
         </div>
         <!-- 创建名单 -->
-        <Modal v-model="newSlStatus" width="600" @on-ok="confirmCreateList" :loading="modalLoading">
-            <div slot="header">
-                <span class="create-list-title">
-                    {{$t('cusMgt.addStuList')}}
-                </span>
+        <Modal v-model="newSlStatus" width="600" footer-hide className="ed-name-modal">
+            <div slot="header" class="modal-header">
+                {{$t('cusMgt.addStuList')}}
+            </div>
+            <div class="edit-name-content">
+                <Form label-position="left" :label-width="70" label-colon @submit.native.prevent>
+                    <FormItem :label="$t('cusMgt.addListType')">
+                        <RadioGroup v-model="type">
+                            <Radio label="create">
+                                <span>
+                                    {{$t('cusMgt.addListType1')}}
+                                </span>
+                            </Radio>
+                            <Radio label="select">
+                                <span>
+                                    {{$t('cusMgt.addListType2')}}
+                                </span>
+                            </Radio>
+                        </RadioGroup>
+                    </FormItem>
+                    <FormItem :label="$t('cusMgt.name')" v-if="type == 'create'">
+                        <Input v-special-char v-model="listName" :placeholder="$t('cusMgt.nameHolder')" style="width: 300px" />
+                    </FormItem>
+                    <FormItem :label="$t('cusMgt.listLabel')" v-else>
+                        <Select v-model="listId" style="width:300px">
+                            <Option v-for="(item,index) in groupList" :value="item.id" :key="index">{{ item.name }}</Option>
+                        </Select>
+                    </FormItem>
+                </Form>
+                <span class="create-list-tips">{{$store.state.userInfo.hasSchool ? $t('cusMgt.createTips1') : $t('cusMgt.createTips2')}}</span>
+                <Button :loading="btnLoading" @click="confirmCreateList" long type="primary" class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
             </div>
-            <Form :label-width="80" label-colon @submit.native.prevent>
-                <FormItem :label="$t('cusMgt.addListType')">
-                    <RadioGroup v-model="type">
-                        <Radio label="create">
-                            <span>
-                                {{$t('cusMgt.addListType1')}}
-                            </span>
-                        </Radio>
-                        <Radio label="select">
-                            <span>
-                                {{$t('cusMgt.addListType2')}}
-                            </span>
-                        </Radio>
-                    </RadioGroup>
-                </FormItem>
-                <FormItem :label="$t('cusMgt.name')" v-if="type == 'create'">
-                    <Input v-special-char v-model="listName" :placeholder="$t('cusMgt.nameHolder')" style="width: 300px" />
-                </FormItem>
-                <FormItem :label="$t('cusMgt.listLabel')" v-else>
-                    <Select v-model="listId" style="width:300px">
-                        <Option v-for="(item,index) in groupList" :value="item.id" :key="index">{{ item.name }}</Option>
-                    </Select>
-                </FormItem>
-            </Form>
-            <span class="create-list-tips">{{$store.state.userInfo.hasSchool ? $t('cusMgt.createTips1') : $t('cusMgt.createTips2')}}</span>
         </Modal>
-        <Modal v-model="addCusStatus" :title="addCusInfo.id ? $t('cusMgt.editCus') : $t('cusMgt.addCus')" @on-cancel="initCusInfo" @on-ok="confirmAddCus" :loading="modalLoading">
-            <Form ref="addCusInfo" :model="addCusInfo" :rules="ruleAddCus">
-                <FormItem prop="name" :label="$t('cusMgt.cusName')">
-                    <Input v-special-char type="text" v-model="addCusInfo.name" :placeholder="$t('cusMgt.nameHolder')"></Input>
-                </FormItem>
-                <FormItem :label="$t('cusMgt.cusCode')" prop="no">
-                    <Input v-special-char type="text" v-model="addCusInfo.no" :placeholder="$t('cusMgt.codeHolder')"></Input>
-                </FormItem>
-                <FormItem :label="$t('cusMgt.cusDesc')" prop="desc">
-                    <Input v-special-char v-model="addCusInfo.desc" type="textarea" :maxlength="200" show-word-limit :autosize="{ minRows: 4, maxRows: 6 }" :placeholder="$t('cusMgt.descHolder')" />
-                </FormItem>
-            </Form>
+        <!-- 添加或修改课程 -->
+        <Modal v-model="addCusStatus" footer-hide @on-cancel="initCusInfo" className="ed-name-modal">
+            <div slot="header" class="modal-header">
+                {{addCusInfo.id ? $t('cusMgt.editCus') : $t('cusMgt.addCus')}}
+            </div>
+            <div class="edit-name-content">
+                <Form ref="addCusInfo" :model="addCusInfo" :rules="ruleAddCus">
+                    <FormItem prop="name" :label="$t('cusMgt.cusName')">
+                        <Input v-special-char type="text" v-model="addCusInfo.name" :placeholder="$t('cusMgt.nameHolder')"></Input>
+                    </FormItem>
+                    <FormItem :label="$t('cusMgt.cusCode')" prop="no">
+                        <Input v-special-char type="text" v-model="addCusInfo.no" :placeholder="$t('cusMgt.codeHolder')"></Input>
+                    </FormItem>
+                    <FormItem :label="$t('cusMgt.cusDesc')" prop="desc">
+                        <Input v-special-char v-model="addCusInfo.desc" type="textarea" :maxlength="200" show-word-limit :autosize="{ minRows: 4, maxRows: 6 }" :placeholder="$t('cusMgt.descHolder')" />
+                    </FormItem>
+                </Form>
+                <Button :loading="btnLoading" @click="confirmAddCus" long type="primary" class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
+            </div>
         </Modal>
         <Modal v-model="addStuStatus" :title="$t('cusMgt.addStu')" width="1200" @on-ok="confirmAddStu">
             <!-- 添加学生 -->
@@ -346,29 +358,32 @@
             <!-- 跨校不能添加学生 -->
             <TipsInfo v-else-if="addStuStatus" :msg="crossSchool"></TipsInfo>
         </Modal>
-        <div class="qr-code-wrap" v-show="showQrStatus" @click="showQrStatus = false">
-            <div class="qr-code-info" @click.stop>
-                <p class="qr-code-title">
-                    {{$t('cusMgt.qrCodeLabel')}}
-                </p>
-                <div id="qrcode" :class="showQrStatus ? 'animated fadeIn':'animated fadeOut'" ref="qrcode" style="padding:15px 25px 20px 25px;background-color:white;width:330px;margin:auto;">
-                </div>
-                <p class="qr-code-text">
-                    (<span style="font-size:17px">{{$t('cusMgt.qrCodeText')}}</span>
-                    {{stuListNo}})
-                </p>
-                <p class="invite-url-text" v-show="inviteUrl" @click="copyUrl">
-                    <Icon type="md-copy" class="copy-link-icon" :title="$t('cusMgt.copyUrl')" />
-                    <span style="font-size:14px">{{$t('cusMgt.inviteUrl')}}</span>
-                    <!-- {{inviteUrl}} -->
+        <QrcodeModal v-model="showQrStatus" :config="qrConfig">
+            <!-- 支持自定义内容 -->
+            <p class="qr-code-text">
+                (<span style="font-size:17px">{{$t('cusMgt.qrCodeText')}}</span>
+                {{stuListNo}})
+            </p>
+        </QrcodeModal>
+        <!-- 修改名单名称 -->
+        <Modal v-model="editClassStatus" footer-hide :title="$t('cusMgt.renameListTitle')" className="ed-name-modal">
+            <div slot="header" class="modal-header">
+                {{$t('cusMgt.renameListTitle')}}
+            </div>
+            <div class="edit-name-content">
+                <p class="edit-name-label">
+                    {{$t('cusMgt.listName')}}
                 </p>
+                <Input v-model="edName" :placeholder="renameBefore" />
+                <Button :loading="btnLoading" @click="confirmRename" long type="primary" class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
             </div>
-        </div>
-        <Modal v-model="editClassStatus" :title="$t('cusMgt.renameListTitle')" @on-ok="confirmRename">
-            {{$t('cusMgt.listName')}}: <Input v-model="edName" :placeholder="renameBefore" style="width: 300px" />
         </Modal>
-        <Modal v-model="removeListStatus" :title="$t('cusMgt.remvListTitle')" @on-ok="removeStuList">
-            <div v-if="removeListStatus" style="padding:20px">
+        <!-- 删除课程名单 -->
+        <Modal v-model="removeListStatus" footer-hide :title="$t('cusMgt.remvListTitle')" @on-ok="removeStuList" className="ed-name-modal">
+            <div slot="header" class="modal-header">
+                {{$t('cusMgt.remvListTitle')}}
+            </div>
+            <div v-if="removeListStatus" class="edit-name-content">
                 <RadioGroup v-model="isPermanent">
                     <Radio label="remove">
                         <span>{{$t('cusMgt.justRmList')}}</span>
@@ -377,23 +392,51 @@
                         <span>{{$t('cusMgt.permDelList')}}</span>
                     </Radio>
                 </RadioGroup>
+                <Button :loading="btnLoading" @click="removeStuList" long type="primary" class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
             </div>
         </Modal>
         <!-- 快速设置IRS -->
-        <Modal v-model="setIrsStatus" :title="$t('cusMgt.editStu')" @on-ok="confirmFastSet">
-            <p class="set-irs-tips">{{$t('cusMgt.irsTips1')}}</p>
-            <p class="set-irs-tips">{{$t('cusMgt.irsTips2')}}</p>
+        <Modal v-model="setIrsStatus" footer-hide @on-ok="confirmFastSet" className="ed-name-modal">
+            <div slot="header" class="modal-header">
+                {{$t('cusMgt.editStu')}}
+            </div>
+            <div class="edit-name-content">
+                <p class="set-irs-tips">{{$t('cusMgt.irsTips1')}}</p>
+                <p class="set-irs-tips">{{$t('cusMgt.irsTips2')}}</p>
+                <Button :loading="btnLoading" @click="confirmFastSet" long type="primary" class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
+            </div>
+
         </Modal>
         <!-- 修改评测名称 -->
-        <Modal v-model="editNameStatus" :title="$t('learnActivity.mgtScEv.edName')" @on-ok="confirmEditName" :loading="modalLoading">
-            <Input v-model="editName" :placeholder="$t('learnActivity.mgtScEv.edNameHolder')" />
+        <Modal v-model="editNameStatus" className="ed-name-modal" footer-hide>
+            <div slot="header" class="modal-header">
+                {{$t('learnActivity.mgtScEv.edName')}}
+            </div>
+            <div class="edit-name-content">
+                <p class="edit-name-label">
+                    {{$t('cusMgt.listName')}}
+                </p>
+                <Input v-model="editName" :placeholder="$t('learnActivity.mgtScEv.edNameHolder')" />
+                <Button :loading="btnLoading" @click="confirmEditName" long type="primary" class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
+            </div>
+        </Modal>
+        <!-- 修改课堂记录名称 -->
+        <Modal v-model="editRdStatus" className="ed-name-modal" footer-hide>
+            <div slot="header" class="modal-header">
+                {{$t('cusMgt.edRdName')}}
+            </div>
+            <div class="edit-name-content">
+                <p class="edit-name-label">
+                    {{$t('cusMgt.listName')}}
+                </p>
+                <Input v-model="editName" :placeholder="$t('cusMgt.edRdName')" />
+                <Button :loading="btnLoading" @click="confirmEditRd" long type="primary" class="confirm-btn">{{ $t('syllabus.confirm') }}</Button>
+            </div>
         </Modal>
     </div>
 </template>
 <script>
-import BlobTool from '@/utils/blobTool.js'
 import { mapGetters } from 'vuex'
-import QRCode from 'qrcodejs2'
 import PersonalPhoto from '@/components/public/personalPhoto/Index.vue'
 import StudentList from '@/components/coursemgt/StudentList.vue'
 import TeaTable from './TeaTable.vue'
@@ -416,6 +459,13 @@ export default {
             }
         }
         return {
+            qrConfig: {
+                title: this.$t('cusMgt.qrCodeLabel'),
+                url: '',//二维码内容 不用转短网址,组件内部处理
+                shareContent: '',//复制链接内容,支持字符串模板,如果包含网址需要处理好短网址
+            },
+            edRdIndex: 0,
+            editRdStatus: false,
             edNameIndex: 0,
             editName: '',
             editNameStatus: false,
@@ -579,7 +629,6 @@ export default {
             tabName: 'activity',
             addCusStatus: false,
             addStuStatus: false,
-            joinQRcode: undefined,
             curCusIndex: 0,
             curClassIndex: 0,
             courseList: [],
@@ -615,13 +664,54 @@ export default {
             }
             return this.$t('cusMgt.listSchoolTips3')
         },
+        editRecordName(index) {
+            this.editRdStatus = true
+            this.edRdIndex = index
+            this.editName = this.curRecordList[index]?.name
+        },
         editEvName(index) {
             this.editNameStatus = true
             this.edNameIndex = index
             this.editName = this.acList[index]?.name
         },
+        // 修改记录名称
+        confirmEditRd() {
+            if (this.editName) {
+                console.log(this.curRecordList[this.edRdIndex])
+                let recordInfo = this.curRecordList[this.edRdIndex]
+                this.btnLoading = true
+                this.$api.lessonRecord.updateLesson({
+                    "lesson_id": recordInfo.id,
+                    "tmdid": recordInfo.tmdid,
+                    "school": recordInfo.school,
+                    "scope": recordInfo.scope,
+                    "grant_types": [{
+                        "grant_type": "up-baseinfo",
+                        "data": {
+                            "name": this.editName,
+                        }
+                    }]
+                }).then(
+                    res => {
+                        if (!res.error) {
+                            this.$Message.success(this.$t('cusMgt.editOk'))
+                            let i = this.recordList.findIndex(item => item.id == recordInfo.id)
+                            if (i > -1) {
+                                this.$set(this.recordList[i], 'name', this.editName)
+                            }
+                            this.editRdStatus = false
+                        }
+                    }).finally(() => {
+                        this.btnLoading = false
+                    })
+            } else {
+                this.$Message.warning(this.$t('learnActivity.mgtScEv.edNameHolder'))
+            }
+        },
+        // 修改活动名称
         confirmEditName() {
             if (this.editName) {
+                this.btnLoading = true
                 this.acList[this.edNameIndex].code = this.acList[this.edNameIndex].code.replace('Exam-', '')
                 this.$api.learnActivity.updExamEndtime({
                     id: this.acList[this.edNameIndex].id,
@@ -641,13 +731,10 @@ export default {
                     }
                 ).finally(() => {
                     this.editNameStatus = false
+                    this.btnLoading = false
                 })
             } else {
                 this.$Message.warning(this.$t('learnActivity.mgtScEv.edNameHolder'))
-                this.modalLoading = false
-                setTimeout(() => {
-                    this.modalLoading = true
-                })
             }
         },
         //导出名单
@@ -853,9 +940,12 @@ export default {
                 stulist.type = 'teach'
                 stulist.scope = 'private'
                 let params = stulist
+                this.btnLoading = true
                 this.$api.common.upsertGroupInfo(params).then(
                     res => {
                         this.$Message.success(this.$t('cusMgt.updOk'))
+                        this.btnLoading = false
+                        this.editClassStatus = false
                         this.teaClassList[this.curClassIndex].listName = this.edName
                         //更新其他课程数据
                         this.courseListShow.forEach(item => {
@@ -881,46 +971,6 @@ export default {
             this.renameBefore = this.teaClassList[this.curClassIndex].listName
             this.editClassStatus = true
         },
-        async copyUrl() {
-            //邀请加入醍摩豆云平台IES教师个人课程
-
-            // 课程名称:英语能力检测
-            // 课程名单:501班
-            // 授课教师:Power
-
-            // 快速加入教师个人课程链接:
-            // https://www.teammodel.net/joinclass?listName=502%E7%8F%AD&tName=Power&listNo=859738&cusName=%E8%8B%B1%E8%AA%9E%E8%83%BD%E5%8A%9B%E6%AA%A2%E6%B8%AC
-
-            // 或登入醍摩豆云平台IES学习主页,输入课程码加入课程:
-            // URL:https://www.teammodel.net/login/student
-
-            // 输入课程邀请码,加入课程 :859738
-
-            let loginUrl = window.location.host
-            let tName = this.$store.state.userInfo.name
-            let listId = this.teaClassList[this.curClassIndex].stulist
-            let listName = this.teaClassList[this.curClassIndex].listName
-            let cusName = this.courseListShow[this.curCusIndex].name
-            let stulistInfo = this.groupList.find(item => {
-                return item.id == listId
-            })
-            let listNo = stulistInfo.no
-            try {
-                let shortUrl = await this.$api.getShortUrl(encodeURI(this.inviteUrl)) //暂不替换,等路由处理好了再替换
-                let shareText = `${this.$t('cusMgt.inviteInfo1')}\n\n${this.$t('cusMgt.inviteInfo2')}${cusName}\n${this.$t('cusMgt.inviteInfo3')}${listName}\n${this.$t('cusMgt.inviteInfo4')}${tName}\n\n${this.$t('cusMgt.inviteInfo5')}\n${shortUrl.result}\n\n${this.$t('cusMgt.inviteInfo6')}\nURL:https://${loginUrl}/login/student\n${this.$t('cusMgt.inviteInfo7')}${listNo}`
-                this.$copyText(shareText).then(
-                    ok => {
-                        this.$Message.success(this.$t("settings.copyModal1"))
-                    },
-                    fail => {
-                        this.$Message.error(this.$t("settings.copyModal2"))
-                    }
-                )
-            } catch (e) {
-                this.$Message.error(this.$t("settings.copyModal2"))
-            }
-
-        },
         initData() {
             this.cusType = [
                 {
@@ -1371,6 +1421,7 @@ export default {
             let index = this.curClassIndex
             this.curClassIndex = 0
             this.courseListShow[this.curCusIndex].schedule.splice(index, 1)
+            this.btnLoading = true
             this.updCusInfo()
             if (this.isPermanent == 'delete') {
                 //删除名单
@@ -1404,40 +1455,17 @@ export default {
                     err => {
                         this.$Message.error(this.$t('teachermgmt.rmvErr'))
                     }
-                )
+                ).finally(() => {
+                    this.btnLoading = false
+                })
             }
         },
         editCus() {
             this.addCusInfo = this._.cloneDeep(this.courseListShow[this.curCusIndex])
             this.addCusStatus = true
         },
-        //创建二维码
-        createQRCode(url) {
-            this.$nextTick(async () => {
-                // 此时已经渲染完成
-                try {
-                    let shortUrl = await this.$api.getShortUrl(encodeURI(url)) //暂不替换,等路由处理好了再替换
-                    if (this.joinQRcode == undefined) {
-                        let qrcode = new QRCode('qrcode', {
-                            width: 280, // 设置宽度,单位像素
-                            height: 280, // 设置高度,单位像素
-                            // text: encodeURI(url), // 编码处理
-                            text: shortUrl.result, // 编码处理
-                            correctLevel: QRCode.CorrectLevel.Q //解决编码后网址太长的问题
-                        })
-                        this.joinQRcode = qrcode
-                    } else {
-                        this.joinQRcode.clear()
-                        this.joinQRcode.makeCode(shortUrl.result)
-                    }
-                    let dom = document.getElementById('qrcode')
-                    if (dom) dom.title = ''
-                } catch (e) {
-                    this.$Message.error(this.$t('cusMgt.qrcodeErr'))
-                }
-            })
-        },
-        showQrCode(index) {
+        async showQrCode(index) {
+            let loginUrl = window.location.host
             let tName = this.$store.state.userInfo.name
             let listId = this.teaClassList[index].stulist
             let listName = this.teaClassList[index].listName
@@ -1446,15 +1474,22 @@ export default {
                 return item.id == listId
             })
             if (stulistInfo) {
-                this.showQrStatus = true
+                //二维码链接
                 this.stuListNo = stulistInfo.no
-                // //这里需要根据站点动态拼接域名
-                console.log(window.location)
                 let host = window.location.origin
                 let callbackUrl = `${host}/joinclass?listName=${listName}&tName=${tName}&listNo=${this.stuListNo}&cusName=${cusName}`
                 this.inviteUrl = callbackUrl
-                console.log(callbackUrl)
-                this.createQRCode(callbackUrl)
+                this.qrConfig.url = callbackUrl
+
+                // 处理分享内容
+                try {
+                    let shortUrl = await this.$api.getShortUrl(encodeURI(this.inviteUrl))
+                    let shareText = `${this.$t('cusMgt.inviteInfo1')}\n\n${this.$t('cusMgt.inviteInfo2')}${cusName}\n${this.$t('cusMgt.inviteInfo3')}${listName}\n${this.$t('cusMgt.inviteInfo4')}${tName}\n\n${this.$t('cusMgt.inviteInfo5')}\n${shortUrl.result}\n\n${this.$t('cusMgt.inviteInfo6')}\nURL:https://${loginUrl}/login/student\n${this.$t('cusMgt.inviteInfo7')}${this.stuListNo}`
+                    this.qrConfig.shareContent = shareText
+                } catch (e) {
+                    this.qrConfig.shareContent = ''
+                }
+                this.showQrStatus = true
             } else {
                 this.$Message.error(this.$t('cusMgt.listExp'))
             }
@@ -1463,17 +1498,9 @@ export default {
         confirmCreateList() {
             if (!this.listName && this.type == 'create') {
                 this.$Message.warning(this.$t('cusMgt.nameWarning'))
-                this.modalLoading = false
-                setTimeout(() => {
-                    this.modalLoading = true
-                }, 0)
             }
             else if (!this.listId && this.type == 'select') {
                 this.$Message.warning(this.$t('cusMgt.selectListTips'))
-                this.modalLoading = false
-                setTimeout(() => {
-                    this.modalLoading = true
-                }, 0)
             }
             else if (this.type == 'create') {
                 let stuList = {
@@ -1485,6 +1512,7 @@ export default {
                     leader: this.$store.state.userInfo.TEAMModelId,
                     members: []
                 }
+                this.btnLoading = true
                 this.saveStuList(stuList, true)
             }
             else if (this.type == 'select') {
@@ -1499,10 +1527,6 @@ export default {
                     })
                     if (res) {
                         this.$Message.warning(`${res.listName}${this.$t('cusMgt.alreadyExist')}`)
-                        this.modalLoading = false
-                        setTimeout(() => {
-                            this.modalLoading = true
-                        }, 0)
                     } else {
                         this.courseListShow[this.curCusIndex].schedule.push({
                             classId: '',
@@ -1514,6 +1538,7 @@ export default {
                             students: s.students,
                             time: []
                         })
+                        this.btnLoading = true
                         this.updCusInfo()
                         this.listId = ''
                     }
@@ -1554,6 +1579,8 @@ export default {
                 }
             ).finally(() => {
                 this.listLoading = false
+                this.btnLoading = false
+                this.setIrsStatus = false
             })
         },
 
@@ -1703,6 +1730,7 @@ export default {
                             creatorId: this.$store.state.userInfo.schoolCode
                         }
                     }
+                    this.btnLoading = true
                     this.$api.courseMgmt.saveOrUpdateCourse(requestData).then(
                         (res) => {
                             if (!res.error) {
@@ -1732,25 +1760,17 @@ export default {
                                 this.$refs['addCusInfo'].resetFields()
                             } else {
                                 this.$Message.error(this.addCusInfo.id ? this.$t('cusMgt.editErr') : this.$t('cusMgt.addErr'))
-                                this.modalLoading = false
-                                setTimeout(() => {
-                                    this.modalLoading = true
-                                }, 0)
                             }
                         },
                         (err) => {
-                            this.modalLoading = false
-                            setTimeout(() => {
-                                this.modalLoading = true
-                            }, 0)
+                            this.btnLoading = false
                         }
-                    )
+                    ).finally(() => {
+                        this.btnLoading = false
+                    })
                 } else {
                     this.$Message.error(this.$t('cusMgt.formTips'));
-                    this.modalLoading = false
-                    setTimeout(() => {
-                        this.modalLoading = true
-                    }, 0)
+                    this.btnLoading = false
                 }
             })
         },
@@ -1771,6 +1791,7 @@ export default {
             }).finally(() => {
                 this.listLoading = false
                 this.newSlStatus = false
+                this.btnLoading = false
                 this.listName = ''
             })
         },
@@ -1964,33 +1985,6 @@ export default {
     },
     activated() {
         this.getActivityList()
-        // let delId = this.$route.query.delId
-        // console.log(this.curAcType)
-        // if (delId) {
-        //     let index, data
-        //     switch (this.curAcType) {
-        //         case 'ev':
-        //             data = this.evList
-        //             break
-        //         case 'vote':
-        //             data = this.voteList
-        //             break
-        //         case 'qu':
-        //             data = this.quList
-        //             break
-        //         case 'hw':
-        //             data = this.hwList
-        //             break
-        //         case 'sl':
-        //             data = this.slList
-        //             break
-        //         default:
-        //             break
-        //     }
-        //     if (data) index = data.findIndex(item => item.id === delId)
-        //     console.log(index)
-        //     if (index > -1) data.splice(index, 1)
-        // }
     },
     watch: {
         '$store.state.userInfo.schoolCode': {
@@ -2168,7 +2162,7 @@ export default {
 <style scoped lang="less">
 @import "./MyCourse.less";
 </style>
-<style>
+<style lang="less">
 .ivu-table-row-hover .item-tools {
     display: inline-block;
 }
@@ -2197,5 +2191,8 @@ export default {
 }
 .class-record-wrap .ivu-list-item:hover {
     background: var(--active-item-start);
+    .edit-ev-name {
+        display: inline-block;
+    }
 }
 </style>

+ 287 - 0
TEAMModelOS/ClientApp/src/view/shareSyllabus/ShareSyllabus.vue

@@ -0,0 +1,287 @@
+<template>
+	<div class="join-wrap">
+		<div class="join-main-box">
+			<p class="join-title">
+				<span>
+					{{ $t('syllabus.saveSyllabus') }}
+				</span>
+			</p>
+			<div v-show="isJoin || isRep" style="margin-bottom:50px">
+				<Icon type="md-checkmark-circle-outline" color="#19be6b" size="120" />
+				<p v-if="isJoin" class="success-tips">{{ $t('syllabus.receivedSuc') }}</p>
+				<!-- <p v-else-if="isRep" class="success-tips">您已收藏成功,请勿重复操作!</p> -->
+			</div>
+			<p v-show="!isJoin && !isRep" class="course-name">{{ params.name }}</p>
+			<div style="width:fit-content;margin: auto;" v-if="!isRep && !isJoin">
+				<p class="info-item">
+					<span class="info-value">
+						{{ params.creatorName }}
+					</span>
+				</p>
+				<p class="info-item" v-show="isJoin || isRep">
+					<span class="info-lable">
+						{{$t('cusMgt.join.cusLabel')}}
+					</span>
+					<span class="info-value">
+						{{cusName}}
+					</span>
+				</p>
+			</div>
+			<div class="join-btn" @click="toLogin()" v-show="!isJoin && !isRep">
+				{{ $t('syllabus.receiveBtn') }}
+			</div>
+		</div>
+	</div>
+</template>
+<script>
+	import jwtDecode from 'jwt-decode'
+	export default {
+		data() {
+			return {
+				params:{},
+				isRep: false,
+				isPC: false,
+				isLogin: false,
+				isJoin: false,
+				tId: '',
+				tName: '',
+				listNo: '',
+				listName: '',
+				cusName: '',
+				code: '',
+				userId: '',
+				userName: '',
+				id_token: '',
+				China: {
+					srvAdr: 'China',
+					clientID: 'c7317f88-7cea-4e48-ac57-a16071f7b884',
+					accAPIUrl: 'https://account-rc.teammodel.cn',
+					coreAPIUrl: 'https://api2.teammodel.cn',
+					domainUrl: [{
+							station: 'product',
+							url: 'https://www.teammodel.cn'
+						},
+						{
+							station: 'test',
+							url: 'https://test.teammodel.cn'
+						},
+					]
+				},
+				Global: {
+					srvAdr: 'Global',
+					clientID: '531fecd1-b1a5-469a-93ca-7984e1d392f2',
+					accAPIUrl: 'https://account.teammodel.net',
+					coreAPIUrl: 'https://api2.teammodel.net',
+					domainUrl: [{
+							station: 'product',
+							url: 'https://www.teammodel.net'
+						},
+						{
+							station: 'test',
+							url: 'https://test.teammodel.net'
+						},
+					]
+				}
+			}
+		},
+		created() {
+			this.params = this.$route.query
+			this.code = this.$route.query.code //登录成功返回的code
+			if (!this.params.id) {
+				this.$Message.error('Link Error')
+			} else if (this.code) {
+				//获取登录信息
+				let addr = this.getServeAddr()
+				let host = addr == 'Global' ? this.Global.coreAPIUrl : this.China.coreAPIUrl
+				let clientId = addr == 'Global' ? this.Global.clientID : this.China.clientID
+				this.$api.service.getToken(host, {
+					grant_type: "authorization_code",
+					client_id: clientId,
+					code: this.code
+				}).then(
+					res => {
+						if (!res.error) {
+							this.id_token = res.id_token
+							let tokenData = jwtDecode(res.id_token)
+							if (tokenData) {
+								this.userId = tokenData.sub
+								this.userName = tokenData.name
+								this.doShare()
+							} else {
+								this.$Message.error(this.$t('cusMgt.join.parseErr'))
+							}
+						} else {
+							this.$Message.error(this.$t('cusMgt.join.getErr'))
+						}
+					},
+					err => {
+						this.$Message.error(this.$t('cusMgt.join.getErr'))
+					}
+				)
+
+			}
+			// 判断移动端还是PC端
+			this.isPC = !(/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent))
+		},
+		methods: {
+			/* 根据册别查询对应课纲树形结构 */
+			getTreeByVolumeId(volume) {
+				return new Promise((r, j) => {
+					this.$api.syllabus.GetTreeByVolume({
+						volumeId: volume.id,
+						volumeCode: volume.code,
+						scope: volume.scope
+					}).then(res => {
+						if (!res.error) {
+							let result = []
+							if(res.tree.length){
+								result = res.tree.map(i => {
+									return {
+										syllabusId:i.id,
+										syllabusName:this.params.name
+									}
+								})
+							}
+							r(result)
+						}
+					})
+				})
+			},
+			async doShare() {
+				let syllabus = await this.getTreeByVolumeId({
+					id: this.params.id,
+					code: 'Volume-' + this.params.creatorId,
+					scope: 'private'
+				})
+				let params = {
+					"school": "",
+					"scope": "private",
+					"tmdInfo": [{
+						"tmdid": this.userId,
+						"tmdname": this.userName
+					}],
+					"type": "share",
+					"issuer": this.params.creatorId,
+					"issuerName": this.params.creatorName,
+					"opt": "add",
+					"syllabus": syllabus,
+					"volumeId": this.params.id,
+					"volumeName": this.params.name
+				}
+				this.$api.syllabus.ShareTree(params).then(res => {
+					if(!res.error && res.code === 200){
+						this.$Message.success(this.$t('syllabus.receivedSuc'))
+						this.isJoin = true
+					}else{
+						this.$Message.success(this.$t('syllabus.saveFailTip'))
+					}
+				})
+			},
+			getServeAddr() {
+				let hostname = window.location.hostname
+				let addr
+				let hostarray = hostname.split('.')
+				if (hostarray[hostarray.length - 1] == 'net') {
+					addr = 'Global'
+				} else {
+					addr = 'China'
+				}
+				return addr
+			},
+			toLogin() {
+				let addr = this.getServeAddr()
+				// let type = process.env.NODE_ENV //product | development
+				let clientId, accUrl
+				//国际站
+				if (addr == 'Global') {
+					clientId = this.Global.clientID
+					accUrl = this.Global.accAPIUrl
+				}
+				// 大陆站
+				else {
+					clientId = this.China.clientID
+					accUrl = this.China.accAPIUrl
+				}
+				let callback = decodeURIComponent(window.location.href)
+				let state = this.$jsFn.getBtwRandom(1000, 9999)
+				let nonce = this.$jsFn.uuid()
+				let loginUrl =
+					`${accUrl}/oauth2/authorize?response_type=code&client_id=${clientId}&state=${state}&nonce=${nonce}&redirect_uri=${encodeURIComponent(callback)}`
+				window.location.href = loginUrl
+			}
+		}
+	}
+</script>
+<style scoped lang="less">
+	.success-tips {
+		color: white;
+		font-size: 16px;
+		margin-top: 20px;
+	}
+
+	.join-wrap {
+		display: flex;
+		flex-direction: column;
+		justify-content: space-evenly;
+		align-items: center;
+		width: 100%;
+		height: 100%;
+		background-image: url("../../assets/image/bak_light.jpg");
+	}
+
+	.join-btn {
+		cursor: pointer;
+		width: 100%;
+		margin: auto;
+		margin-top: 60px;
+		text-align: center;
+		border: 1px solid rgba(25, 190, 107, 0.5);
+		// color: rgba(25, 190, 107, 1);
+		color: white;
+		padding: 4px 30px;
+		border-radius: 5px;
+		font-size: 16px;
+		letter-spacing: 2px;
+		font-weight: 400;
+		user-select: none;
+		background: rgba(25, 190, 107, 0.5);
+	}
+
+	.course-name {
+		color: white;
+		margin-bottom: 15px;
+		font-size: 30px;
+		// font-family: cursive;
+	}
+
+	.join-main-box {
+		max-width: 90%;
+		width: fit-content;
+		text-align: center;
+
+		.info-item {
+			margin-top: 20px;
+			font-size: 15px;
+			width: fit-content;
+		}
+
+		.info-lable {
+			color: #a5a5a5;
+		}
+
+		.info-value {
+			color: #eeeeee;
+		}
+	}
+
+	.join-title {
+		position: absolute;
+		top: 15px;
+		text-align: center;
+		width: 100%;
+		left: 0px;
+		border-bottom: 1px dashed #5f5f5f;
+		padding-bottom: 8px;
+		color: #fff;
+	}
+</style>

+ 27 - 25
TEAMModelOS/ClientApp/src/view/sso/Index.vue

@@ -94,29 +94,31 @@ export default {
         },
         loginProcess(idRes) { // 登入用function
             this.clearData() //这里暂定解决登录失败的问题
-            localStorage.setItem("id_token", idRes.id_token)
-            localStorage.setItem("access_token", idRes.access_token)
-            localStorage.setItem("expires_in", idRes.expires_in)
-            this.$api.login.teacherLogin(idRes).then(res => {
-                //設定權限並登入
-                User.login(res).then(res => {
-                    if (res) {
-                        this.$store.commit('setUserInfo', {
-                            TEAMModelId: res.id,
-                            name: res.name,
-                            schoolCode: res.defaultschool
-                        })
-                        if (res.toArea) {
-                            localStorage.setItem('platform', 'area')
-                            this.$router.push({ path: '/area' })
-                        } else {
-                            localStorage.setItem('platform', 'school')
-                            let homePath = this.$store.state.config.srvAdr == 'China' ? 'home' : 'myCourse'
-                            this.$router.push({ name: homePath })
-                        }
-                    }
-                })
-            })
+            // localStorage.setItem("id_token", idRes.id_token)
+            // localStorage.setItem("access_token", idRes.access_token)
+            // localStorage.setItem("expires_in", idRes.expires_in)
+			sessionStorage.setItem('identity','teacher')
+            this.$loginTools.teacherLogin(idRes)
+			// this.$api.login.teacherLogin(idRes).then(res => {
+            //     //設定權限並登入
+            //     User.login(res).then(res => {
+            //         if (res) {
+            //             this.$store.commit('setUserInfo', {
+            //                 TEAMModelId: res.id,
+            //                 name: res.name,
+            //                 schoolCode: res.defaultschool
+            //             })
+            //             if (res.toArea) {
+            //                 localStorage.setItem('platform', 'area')
+            //                 this.$router.push({ path: '/area' })
+            //             } else {
+            //                 localStorage.setItem('platform', 'school')
+            //                 let homePath = this.$store.state.config.srvAdr == 'China' ? 'home' : 'myCourse'
+            //                 this.$router.push({ name: homePath })
+            //             }
+            //         }
+            //     })
+            // })
 
         },
     },
@@ -135,7 +137,7 @@ export default {
                     })
                     break
                 case '200':
-                    //已绑定,直接登录
+                    //已绑定省平台,直接登录
                     // 验证返回参数
                     if (this.routerData.id_token && this.routerData.access_token && this.routerData.expires_in && this.routerData.token_type) {
                         this.loginProcess({
@@ -152,7 +154,7 @@ export default {
                     }
                     break
                 case '4':
-                    // 未绑定,需要登录绑定
+                    // 省平台账号未绑定,需要登录绑定
                     this.$Modal.confirm({
                         title: '实名认定',
                         content: `是否前往手机实名认证页面?`,

+ 19 - 15
TEAMModelOS/ClientApp/src/view/syllabus/Syllabus.vue

@@ -198,7 +198,12 @@
 				</div>
 			</div>
 		</div>
-
+		<QrcodeModal v-model="shareQrModal" :config="qrConfig">
+		    <!-- 支持自定义内容 -->
+		    <p class="qr-code-text">
+		        {{ curVolume.name }}
+		    </p>
+		</QrcodeModal>
 		<!--上传文件-->
 		<Modal v-model="isUploadModal" width="800" footer-hide class="tree-modal add-volume-modal tree-upload-modal">
 			<div class="modal-header" slot="header">
@@ -493,6 +498,12 @@
 				flatArr: [],
 				myCreateChapters: [],
 				isSaveSyllabus: false,
+				qrConfig: {
+				    title: this.$t('syllabus.shareSyllabus'),
+				    url: '',//二维码内容 不用转短网址,组件内部处理
+				    shareContent: '',//复制链接内容,支持字符串模板,如果包含网址需要处理好短网址
+				},
+				shareQrModal:false,
 			}
 		},
 		created() {
@@ -1201,19 +1212,12 @@
 			/* 个人课纲二维码分享 */
 			doShareQrCode(){
 				console.log(this.curVolume)
-				let dom = document.createElement('div')
-				let qrcode = new QRCode(dom, {
-					width: 320, // 设置宽度,单位像素
-					height: 320, // 设置高度,单位像素
-					text: this.curVolume.name, // 设置二维码内容或跳转地址
-				})
-				setTimeout(() => {
-					let base64 = dom.getElementsByTagName('img')[0].currentSrc
-					this.$hevueImgPreview({
-					  url: base64,
-					  keyboard: true
-					})
-				}, 500)
+				let { creatorName,creatorId,name,id } = this.curVolume
+				let host = window.location.origin
+				let callbackUrl = `${host}/shareSyllabus?creatorName=${creatorName}&creatorId=${creatorId}&name=${name}&id=${id}`
+				this.qrConfig.url = callbackUrl
+				this.qrConfig.shareContent = callbackUrl
+				this.shareQrModal = true
 			},
 			/* 点击收藏复制分享的课纲 */
 			doCopy() {
@@ -2113,7 +2117,7 @@
 						this.isLoading = false
 						break;
 					case 'link':
-						window.open(item.link);
+						window.open(/^(http:|https:)/i.test(item.link) ? item.link : "http://" + item.link)
 						break;
 					case 'other':
 						this.$Message.warning(this.$t('syllabus.noPreview'))

+ 1 - 1
TEAMModelOS/ClientApp/src/view/teachermgmt/components/personnel/Index.vue

@@ -404,7 +404,7 @@ export default {
                             // data.name = this.$store.state.user?.schoolProfile?.school_base?.name
                             // data.random = '123456'
                             let url = `${window.location.origin}/hita/join-school?ts=${res.nowtime}&school=${this.$store.state.userInfo.schoolCode}&sname=${this.$store.state.user?.schoolProfile?.school_base?.name}`
-                            let shortUrl = await this.$api.getShortUrl(encodeURI(url)) //暂不替换,等路由处理好了再替换
+                            // let shortUrl = await this.$api.getShortUrl(encodeURI(url)) //暂不替换,等路由处理好了再替换
                             let qrcode = new QRCode('teacher-qr-code', {
                                 width: 280, // 设置宽度,单位像素
                                 height: 280, // 设置高度,单位像素

+ 6 - 6
TEAMModelOS/ClientApp/src/view/train/Create.vue

@@ -354,6 +354,7 @@ export default {
             }
         }
         return {
+            createStatus: {},
             formatTarget: [],
             updHeader: {},
             modalLoading: true,
@@ -661,18 +662,21 @@ export default {
             // 如果新建问卷,需要保存问卷
             let surveyId = this.$jsFn.uuid()
             if (this.trainInfo.setting.includes('survey')) {
+                this.$set(this.createStatus, 'survey', 0)
                 this.beginSaveSurvey(surveyId)
             }
 
             // 如果新建问卷,需要保存问卷
             let examId = this.$jsFn.uuid()
             if (this.trainInfo.setting.includes('exam')) {
+                this.$set(this.createStatus, 'exam', 0)
                 this.beginSaveExam(examId)
             }
 
             //作业活动
             let workId = this.$jsFn.uuid()
             if (this.trainInfo.setting.includes('hw')) {
+                this.$set(this.createStatus, 'hw', 0)
                 this.beginSaveHw(workId)
             }
             let key = this.trainList[0].id
@@ -751,13 +755,9 @@ export default {
             this.doUploadBlob(bInfo, items, 'survey').then(
                 res => {
                     // // 保存数据到cosmos
-                    // this.saveSurvey(quId)
+                    this.saveSurvey(id, answers)
                 }
-            ).finally(() => {
-                //暂时写在这里,保存能够保存成功
-                // 保存数据到cosmos
-                this.saveSurvey(id, answers)
-            })
+            )
         },
         saveSurvey(id, answers) {
             let key = this.trainList[0].id

+ 4 - 4
TEAMModelOS/ClientApp/src/view/train/TrainDetail.vue

@@ -1421,13 +1421,13 @@ export default {
                     let qrcode = new QRCode('fullqrcode', {
                         width: 320, // 设置宽度,单位像素
                         height: 320, // 设置高度,单位像素
-                        text: url, // 设置二维码内容或跳转地址
+                        text: shortUrl.result, // 设置二维码内容或跳转地址
                         correctLevel: QRCode.CorrectLevel.L //解决编码后网址太长的问题
                     })
                     this.fullQR = qrcode
                 } else {
                     this.fullQR.clear()
-                    this.fullQR.makeCode(url)
+                    this.fullQR.makeCode(shortUrl.result)
                 }
                 let dom = document.getElementById('fullqrcode')
                 if (dom) dom.title = ''
@@ -1444,13 +1444,13 @@ export default {
                     let qrcode = new QRCode('sign-qr-code', {
                         width: 150, // 设置宽度,单位像素
                         height: 150, // 设置高度,单位像素
-                        text: url, // 设置二维码内容或跳转地址
+                        text: shortUrl.result, // 设置二维码内容或跳转地址
                         correctLevel: QRCode.CorrectLevel.L //解决编码后网址太长的问题
                     })
                     this.signQRcode = qrcode
                 } else {
                     this.signQRcode.clear()
-                    this.signQRcode.makeCode(url)
+                    this.signQRcode.makeCode(shortUrl.result)
                 }
                 let dom = document.getElementById('qrcode')
                 if (dom) dom.title = ''

+ 2 - 2
TEAMModelOS/Controllers/Both/LessonRecordController.cs

@@ -102,11 +102,11 @@ namespace TEAMModelOS.Controllers
                         element.TryGetProperty("subjectId", out JsonElement _subjectId);
                         element.TryGetProperty("grade", out JsonElement _grade);
                         element.TryGetProperty("category", out JsonElement _category);
-                        if (_name.ValueKind.Equals(JsonValueKind.String) && string.IsNullOrWhiteSpace($"{_name}"))
+                        if (_name.ValueKind.Equals(JsonValueKind.String) && !string.IsNullOrWhiteSpace($"{_name}"))
                         {
                             lessonRecord.name = $"{_name}";
                         }
-                        if (_subjectId.ValueKind.Equals(JsonValueKind.String) && string.IsNullOrWhiteSpace($"{_subjectId}"))
+                        if (_subjectId.ValueKind.Equals(JsonValueKind.String) && !string.IsNullOrWhiteSpace($"{_subjectId}"))
                         {
                             lessonRecord.subjectId = $"{_subjectId}";
                         }

+ 10 - 12
TEAMModelOS/Controllers/Client/HiTeachController.cs

@@ -83,7 +83,7 @@ namespace TEAMModelOS.Controllers.Client
             if (!request.TryGetProperty("tmdid", out JsonElement _tmdid)) return BadRequest();
             request.TryGetProperty("school", out JsonElement _school);
             if (!request.TryGetProperty("scope", out JsonElement _scope)) return BadRequest();
-            if (!request.TryGetProperty("grant_types", out JsonElement _grant_types)) return BadRequest();
+            request.TryGetProperty("grant_types", out JsonElement _grant_types);
             string tbname ;
             string code ;
 
@@ -104,24 +104,22 @@ namespace TEAMModelOS.Controllers.Client
             try
             {
                 LessonRecord lessonRecord = await client.GetContainer(Constant.TEAMModelOS, tbname).ReadItemAsync<LessonRecord>($"{_lessonId}", new PartitionKey(code));
+                List<LessonUpdate> updates = _grant_types.ToObject<List<LessonUpdate>>();
                 if (_grant_types.ValueKind.Equals(JsonValueKind.Array))
                 {
-                    List<LessonUpdate> updates = _grant_types.ToObject<List<LessonUpdate>>();
-                    if (updates.IsNotEmpty())
+                    if (updates.IsEmpty())
                     {
-                        var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
-                        var messageChange = new ServiceBusMessage(request.ToJsonString());
-                        messageChange.ApplicationProperties.Add("name", "LessonRecordEvent");
-                        await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange);
-                        return Ok(new { status = 200});
-                    }
-                    else {
-                        return BadRequest();
+                        updates.Add(new LessonUpdate { grant_type = "up-base" });
                     }
                 }
                 else {
-                    return BadRequest();
+                    updates.Add(new LessonUpdate { grant_type = "up-base" });
                 }
+                var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
+                var messageChange = new ServiceBusMessage(request.ToJsonString());
+                messageChange.ApplicationProperties.Add("name", "LessonRecordEvent");
+                await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange);
+                return Ok(new { status = 200 });
             }
             catch (CosmosException ex) when (ex.Status==404 ) {
                 return BadRequest("课堂记录不存在");

+ 67 - 3
TEAMModelOS/Controllers/Teacher/TeacherCommonController.cs

@@ -62,7 +62,7 @@ namespace TEAMModelOS.Controllers
                     stulist.Add(x.stulist);
                 }
             });
-            List<string> types = new List<string> { "Exam", "Survey", "Vote" };
+            List<string> types = new List<string> { "Exam", "Survey", "Vote","Homework" };
             List<MQActivity> datas = new List<MQActivity>();
             List<KeyValuePair<string, int>> count = new List<KeyValuePair<string, int>>();
             foreach (var type in types)
@@ -139,11 +139,75 @@ namespace TEAMModelOS.Controllers
                 KeyValuePair<string, int> valuePair = new KeyValuePair<string, int>(type, acount);
                 count.Add(valuePair);
             }
-            return Ok(new { totalCount = count, goingDatas = datas });
-        }
+            //课程统计 个人和学校  分别对应的教学的班级有多少
+            List<CourseCount> privateCourse = new List<CourseCount>();
+            string courseSql = $" SELECT a.teacherId,a.classId,  a.stulist,c.id,c.name FROM c  join a in c.schedule where a.teacherId='{id}'  ";
+            await foreach(var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<CourseCount>(courseSql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{id}") })){
+                privateCourse.Add(item);
+            }
+            List<CourseCount> schoolCourse = new List<CourseCount>();
+            if (!string.IsNullOrEmpty(school)) {
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<CourseCount>(courseSql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{school}") }))
+                {   
+                    schoolCourse.Add(item);
+                }
+            }
+            //涉及的课程清单数量(去重),与排课无关,排课涉及周期问题,暂不进行统计
+            int privateCourseCount= privateCourse.Select(x => x.id).ToHashSet().Count();
+            int schoolCourseCount = schoolCourse.Select(x => x.id).ToHashSet().Count();
+            //行政班教学数量,去重。
+            HashSet<string> classIds = new HashSet<string>();
+            HashSet<string> teachIds = new HashSet<string>();
+            HashSet<string> stulists = new HashSet<string>();
+            privateCourse.ForEach(x => {
+                if (!string.IsNullOrWhiteSpace(x.classId))
+                {
+                    classIds.Add(x.classId);
+                }
+                if (!string.IsNullOrWhiteSpace(x.stulist))
+                {
+                    stulists.Add(x.stulist);
+                }
+            });
+            schoolCourse.ForEach(x => {
+                if (!string.IsNullOrWhiteSpace(x.classId))
+                {
+                    classIds.Add(x.classId);
+                }
+                if (!string.IsNullOrWhiteSpace(x.stulist))
+                {
+                    teachIds.Add(x.stulist);
+                }
+            });
 
+            string countItemPaperSql = $" SELECT value(count(1)) FROM c   ";
+            int privateItemCount = 0;
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<int>(countItemPaperSql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{id}") }))
+            {
+                privateItemCount=item;
+            }
+            int privatePaperCount = 0;
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<int>(countItemPaperSql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Paper-{id}") }))
+            {
+                privatePaperCount = item;
+            }
 
+            int privateSyllabusCount = 0;
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<int>(countItemPaperSql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Syllabus-{id}") }))
+            {
+                privateSyllabusCount = item;
+            }
+            return Ok(new { totalCount = count, goingDatas = datas, privateCourseCount, schoolCourseCount , classIdsCount= classIds.Count(), teachIdsCount= teachIds.Count(),   stulistsCount = stulists.Count(), privateItemCount , privatePaperCount, privateSyllabusCount });
+        }
 
+
+        public class CourseCount{
+            public string id { get; set; }
+            public string teacherId { get; set; }
+            public string classId { get; set; }
+            public string stulist { get; set; }
+            public string name { get; set; }
+        }
         /// <summary>
         /// 教师端,查询活动所有活动类型的列表,班主任,任课教师等
         /// 执教班级

+ 3 - 1
TEAMModelOS/Controllers/Third/Sc/ScDataInitController.cs

@@ -233,6 +233,7 @@ namespace TEAMModelOS.Controllers.Third
                         x.Email = tt.Email;
                         x.areaId = $"{areaId}";
                         x.PartitionKey = "ScTeacher";
+                        x.tmdid = null;
                         var school = ScSchools.Find(s => s.schoolid == x.SchoolID);
                         x.schoolCode = school?.schoolCode;
                     }
@@ -280,6 +281,7 @@ namespace TEAMModelOS.Controllers.Third
                         x.Email = tt.Email;
                         x.areaId = $"{areaId}";
                         x.PartitionKey = "ScTeacher";
+                        x.tmdid = null;
                         var school = ScSchools.Find(s => s.schoolid == x.SchoolID);
                         x.schoolCode = school?.schoolCode;
                     }
@@ -344,7 +346,7 @@ namespace TEAMModelOS.Controllers.Third
             {
                 await table.SaveOrUpdateAll(updateTch);
             }
-            return Ok(new { update = updateTch.Select(x => new { x.areaId, x.PXID, x.TID, x.TeacherName, x.tmdid, x.SchoolName, x.DisName }), ScTeachers });
+            return Ok(new { addTeachers, update = updateTch.Select(x => new { x.areaId, x.PXID, x.TID, x.TeacherName, x.tmdid, x.SchoolName, x.DisName }), ScTeachers });
         }
         /// <summary>
         ///1. 检查学校是否有同名的

+ 13 - 3
TEAMModelOS/Controllers/XTest/TestController.cs

@@ -1,3 +1,4 @@
+using Azure;
 using Azure.Cosmos;
 using Azure.Messaging.ServiceBus;
 using Azure.Storage.Blobs.Models;
@@ -653,18 +654,27 @@ namespace TEAMModelOS.Controllers
         [HttpPost("get-ip")]
         public async Task<IActionResult> GetIp(JsonElement request)
         {
-            LessonBase lessonBases = request.ToObject< LessonBase>();
+
+
+            try {
+                BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient("hbcn").GetBlobClient($"/111/IES/base.json").DownloadContentAsync();
+                LessonBase lessonBase = baseblobDownload.Content.ToObjectFromJson<LessonBase>();
+            
+            } catch (RequestFailedException ex)when(ex.Status==404) {
+                return BadRequest("文件不存在!");
+            }
+            LessonBase lessonBases = request.ToObject<LessonBase>();
 
             //List<TmdInfo> tmds= request.ToObject<List<TmdInfo>>();
             //var content = new StringContent(tmds.Select(x=>x.id).ToJsonString(), Encoding.UTF8, "application/json");
             //string json = await _coreAPIHttpService.GetUserInfos(content);
 
-           
+
             //string _researchKey = Regex.Replace($"{request.GetProperty("key")}", "[ \\[ \\] \\^ \\-|()【】/' {}_*×――(^)$%~!@#$…&%¥—+=<>《》!!???::•`·、。,;,.;\"‘’“”-]", " ");
             //string[] mm = Regex.Split(_researchKey, "\\s+", RegexOptions.IgnoreCase);
             //var token = await CoreTokenExtensions.CreateAccessToken("c7317f88-7cea-4e48-ac57-a16071f7b884", "kguxh:V.PLmxBdaI@jnrTrDSth]A3346", "China");
             //string ip = await _searcher.SearchIpAsync($"{request.GetProperty("ip")}");
-           // return Ok(new { activity, ip, token.AccessToken,token.TokenType,token.IdToken, mm });
+            // return Ok(new { activity, ip, token.AccessToken,token.TokenType,token.IdToken, mm });
             return Ok(lessonBases);
         }
 

+ 3 - 3
TEAMModelOS/TEAMModelOS.csproj

@@ -32,9 +32,9 @@
     <SpaRoot>ClientApp\</SpaRoot>
     <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
     <UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-    <Version>5.2203.16</Version>
-    <AssemblyVersion>5.2203.16.1</AssemblyVersion>
-    <FileVersion>5.2203.16.1</FileVersion>
+    <Version>5.2203.17</Version>
+    <AssemblyVersion>5.2203.17.1</AssemblyVersion>
+    <FileVersion>5.2203.17.1</FileVersion>
     <Description>TEAMModelOS(IES5)</Description>
     <PackageReleaseNotes>6.0版本说明</PackageReleaseNotes>
     <PackageId>TEAMModelOS</PackageId>