Sfoglia il codice sorgente

Merge branch 'beta'

lsc 1 anno fa
parent
commit
991627f2ab
64 ha cambiato i file con 4514 aggiunte e 474 eliminazioni
  1. 1 1
      dist/index.html
  2. 0 0
      dist/static/css/app.3afa3c622e1cc5a4f8bfe4592e65ea9e.css
  3. 0 0
      dist/static/css/app.3afa3c622e1cc5a4f8bfe4592e65ea9e.css.map
  4. 0 0
      dist/static/css/app.3b7ea0cdcda135c07e7f45387f91673d.css
  5. 0 0
      dist/static/css/app.3b7ea0cdcda135c07e7f45387f91673d.css.map
  6. BIN
      dist/static/img/guidebook.040440e.png
  7. BIN
      dist/static/img/guidebtn.ba1bdcf.png
  8. BIN
      dist/static/img/helloworldQs.68de2a9.gif
  9. 0 0
      dist/static/js/app.558d332d6613a7d8ae2d.js
  10. 0 0
      dist/static/js/app.558d332d6613a7d8ae2d.js.map
  11. 0 0
      dist/static/js/manifest.571c38d63f24b1ae9e16.js.map
  12. 2 2
      src/App.vue
  13. 8 1
      src/assets/css/button.css
  14. 5 0
      src/assets/icon/contrastObservation/refresh.svg
  15. 15 0
      src/assets/icon/contrastObservation/titleIcon.svg
  16. 11 0
      src/assets/icon/course/aiEdit.svg
  17. BIN
      src/assets/icon/pblCourse/DiagonalLine.png
  18. BIN
      src/assets/icon/pblCourse/FrameLeft.png
  19. BIN
      src/assets/icon/pblCourse/FrameRig.png
  20. BIN
      src/assets/icon/pblCourse/addPro.png
  21. BIN
      src/assets/icon/pblCourse/addTitImg.png
  22. BIN
      src/assets/icon/pblCourse/cardimg.png
  23. BIN
      src/assets/icon/pblCourse/chevronRight.png
  24. BIN
      src/assets/icon/pblCourse/del.png
  25. BIN
      src/assets/icon/pblCourse/file1.png
  26. BIN
      src/assets/icon/pblCourse/guidebook.png
  27. BIN
      src/assets/icon/pblCourse/guidebtn.png
  28. BIN
      src/assets/icon/pblCourse/helloworldQs.gif
  29. BIN
      src/assets/icon/pblCourse/helloworldQs.png
  30. BIN
      src/assets/icon/pblCourse/huishou.png
  31. BIN
      src/assets/icon/pblCourse/linehui.png
  32. BIN
      src/assets/icon/pblCourse/priFileImg.png
  33. BIN
      src/assets/icon/test/type_time_icon.png
  34. 185 4
      src/components/pages/aiAddCourse/addCourse.vue
  35. 2 2
      src/components/pages/aiAddCourse/templateDialog.vue
  36. 1 1
      src/components/pages/classroomObservation/components/analysisItem.vue
  37. 18 6
      src/components/pages/classroomObservation/components/baseMessage.vue
  38. 5 2
      src/components/pages/classroomObservation/index.vue
  39. 88 0
      src/components/pages/contrastObservation/component/chart.vue
  40. 1452 0
      src/components/pages/contrastObservation/index.vue
  41. 19 1
      src/components/pages/course.vue
  42. 124 0
      src/components/pages/pblCourse/component/bars.vue
  43. 3 2
      src/components/pages/pblCourse/component/chatArea.vue
  44. 22 10
      src/components/pages/pblCourse/component/doWorkArea.vue
  45. 1 1
      src/components/pages/pblCourse/component/procedureArea.vue
  46. 1 1
      src/components/pages/pblCourse/component/selectTopicDialog.vue
  47. 252 0
      src/components/pages/pblCourse/component/vpdf.vue
  48. 621 258
      src/components/pages/pblCourse/component/work.vue
  49. 674 0
      src/components/pages/pblCourse/guide.vue
  50. 359 167
      src/components/pages/pblCourse/index.vue
  51. 23 1
      src/components/pages/test/add/components/checkOrder.vue
  52. 192 0
      src/components/pages/test/add/components/timeBox/index.vue
  53. 98 0
      src/components/pages/test/add/components/timeBox/time.vue
  54. 1 1
      src/components/pages/test/add/edit/check/eva.vue
  55. 15 3
      src/components/pages/test/add/edit/check/index.vue
  56. 103 0
      src/components/pages/test/add/edit/check/time.vue
  57. 12 1
      src/components/pages/test/add/edit/edit/index.vue
  58. 5 0
      src/components/pages/test/add/minxins/minxin.js
  59. 10 0
      src/components/pages/test/add/setInfo/manualCreated.vue
  60. 42 4
      src/components/pages/test/check/index.vue
  61. 1 1
      src/components/pages/testStudent/view/component/eva.vue
  62. 105 0
      src/components/pages/testStudent/view/component/time.vue
  63. 20 4
      src/components/pages/testStudent/view/component/topic.vue
  64. 18 0
      src/router/index.js

+ 1 - 1
dist/index.html

@@ -32,7 +32,7 @@
       width: 100%;
       background: #e6eaf0;
       font-family: '黑体';
-    }</style><link href=./static/css/app.3b7ea0cdcda135c07e7f45387f91673d.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.571c38d63f24b1ae9e16.js></script><script type=text/javascript src=./static/js/vendor.3cd0a0187ca1f70ded67.js></script><script type=text/javascript src=./static/js/app.ac40c90e6e1793b476e3.js></script></body></html><script>function stopSafari() {
+    }</style><link href=./static/css/app.3afa3c622e1cc5a4f8bfe4592e65ea9e.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.571c38d63f24b1ae9e16.js></script><script type=text/javascript src=./static/js/vendor.3cd0a0187ca1f70ded67.js></script><script type=text/javascript src=./static/js/app.558d332d6613a7d8ae2d.js></script></body></html><script>function stopSafari() {
     //阻止safari浏览器双击放大功能
     let lastTouchEnd = 0  //更新手指弹起的时间
     document.documentElement.addEventListener("touchstart", function (event) {

File diff suppressed because it is too large
+ 0 - 0
dist/static/css/app.3afa3c622e1cc5a4f8bfe4592e65ea9e.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/app.3afa3c622e1cc5a4f8bfe4592e65ea9e.css.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/app.3b7ea0cdcda135c07e7f45387f91673d.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/app.3b7ea0cdcda135c07e7f45387f91673d.css.map


BIN
dist/static/img/guidebook.040440e.png


BIN
dist/static/img/guidebtn.ba1bdcf.png


BIN
dist/static/img/helloworldQs.68de2a9.gif


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/app.558d332d6613a7d8ae2d.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/app.558d332d6613a7d8ae2d.js.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/manifest.571c38d63f24b1ae9e16.js.map


+ 2 - 2
src/App.vue

@@ -412,11 +412,11 @@ html::-webkit-scrollbar-thumb {
 }
 
 .text_tooltip {
-  max-width: 350px;
+  max-width: 350px !important;
 }
 
 .text_tooltip2 {
-  max-width: 400px;
+  max-width: 400px !important;
 }
 
 .getOverView{

+ 8 - 1
src/assets/css/button.css

@@ -198,6 +198,7 @@
   background-image: url(../icon/new/icon_setting.png);
 }
 
+.r_pub_button_edit,
 .r_pub_button_op,
 .r_pub_button_retrun {
   color: #0061FF;
@@ -296,6 +297,7 @@
 .pub_test_btn_group::before,
 .pub_test_btn_course::before,
 .pub_test_btn_eva::before,
+.pub_test_btn_time::before,
 .pub_test_btn_file::before {
   content: "";
   width: 18px;
@@ -329,6 +331,9 @@
 .pub_test_btn_eva::before {
   background-image: url(../icon/test/type_eva_icon.png);
 }
+.pub_test_btn_time::before {
+  background-image: url(../icon/test/type_time_icon.png);
+}
 
 .test_icon{
   display: inline-block;
@@ -359,7 +364,9 @@
 .test_eva_file{
   background-image: url('../icon/test/type_eva_icon.png');
 }
-
+.test_icon_time{
+  background-image: url('../icon/test/type_time_icon.png');
+}
 
 .dataBoard_check_box {
   display: flex;

+ 5 - 0
src/assets/icon/contrastObservation/refresh.svg

@@ -0,0 +1,5 @@
+<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="0.5" y="0.5" width="31" height="31" rx="5.5" fill="white"/>
+<rect x="0.5" y="0.5" width="31" height="31" rx="5.5" stroke="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.10986 20.8591L9.23461 17.3799L9.81127 18.6997C10.8536 21.0853 13.2332 22.75 15.9999 22.75C19.7279 22.75 22.7499 19.7279 22.7499 16L24.2499 16C24.2499 20.5563 20.5563 24.25 15.9999 24.25C13.1037 24.25 10.5572 22.7577 9.08558 20.5019L8.39002 21.6409L7.10986 20.8591ZM15.9999 9.25C12.272 9.25 9.24994 12.2721 9.24994 16L7.74994 16C7.74994 11.4437 11.4436 7.75 15.9999 7.75C18.8962 7.75 21.4426 9.24233 22.9143 11.4981L23.6099 10.3591L24.89 11.1409L22.7653 14.6201L22.1886 13.3003C21.1463 10.9147 18.7667 9.25 15.9999 9.25Z" fill="#3681FC"/>
+</svg>

+ 15 - 0
src/assets/icon/contrastObservation/titleIcon.svg

@@ -0,0 +1,15 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<circle cx="8.125" cy="8.125" r="6.25" fill="#489BFF"/>
+<g filter="url(#filter0_b_139_4711)">
+<circle cx="11.875" cy="11.875" r="6.25" fill="white" fill-opacity="0.2"/>
+<circle cx="11.875" cy="11.875" r="6" stroke="white" stroke-opacity="0.4" stroke-width="0.5"/>
+</g>
+<defs>
+<filter id="filter0_b_139_4711" x="1.625" y="1.625" width="20.5" height="20.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feGaussianBlur in="BackgroundImageFix" stdDeviation="2"/>
+<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_139_4711"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_139_4711" result="shape"/>
+</filter>
+</defs>
+</svg>

+ 11 - 0
src/assets/icon/course/aiEdit.svg

@@ -0,0 +1,11 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_116_14)">
+<path d="M12.1088 14.9675H8.39495L7.67614 17.5H5.3999L9.23357 5.40002H11.1504L14.9841 17.5H12.7078L12.1088 14.9675ZM8.87416 12.9977H11.5098L10.192 8.49537L8.87416 12.9977ZM17.4999 17.5H15.3435V5.40002H17.4999V17.5Z" fill="#4F4F4F"/>
+<path d="M12.0094 1.54089C6.34728 1.54089 1.70752 6.10201 1.70752 11.7641C1.70752 17.4262 6.34728 22.0659 12.0094 22.0659C17.6714 22.0659 22.3112 17.4262 22.3112 11.7641C22.3112 6.10201 17.6714 1.54089 12.0094 1.54089ZM12.0094 21.0436C6.89776 21.0436 2.72984 16.8757 2.72984 11.7641C2.72984 6.65249 6.89776 2.48457 12.0094 2.48457C17.121 2.48457 21.2889 6.65249 21.2889 11.7641C21.2889 16.8757 17.121 21.0436 12.0094 21.0436Z" fill="#4F4F4F" stroke="#4F4F4F" stroke-width="0.8"/>
+</g>
+<defs>
+<clipPath id="clip0_116_14">
+<rect width="22" height="22" fill="white" transform="translate(1 1)"/>
+</clipPath>
+</defs>
+</svg>

BIN
src/assets/icon/pblCourse/DiagonalLine.png


BIN
src/assets/icon/pblCourse/FrameLeft.png


BIN
src/assets/icon/pblCourse/FrameRig.png


BIN
src/assets/icon/pblCourse/addPro.png


BIN
src/assets/icon/pblCourse/addTitImg.png


BIN
src/assets/icon/pblCourse/cardimg.png


BIN
src/assets/icon/pblCourse/chevronRight.png


BIN
src/assets/icon/pblCourse/del.png


BIN
src/assets/icon/pblCourse/file1.png


BIN
src/assets/icon/pblCourse/guidebook.png


BIN
src/assets/icon/pblCourse/guidebtn.png


BIN
src/assets/icon/pblCourse/helloworldQs.gif


BIN
src/assets/icon/pblCourse/helloworldQs.png


BIN
src/assets/icon/pblCourse/huishou.png


BIN
src/assets/icon/pblCourse/linehui.png


BIN
src/assets/icon/pblCourse/priFileImg.png


BIN
src/assets/icon/test/type_time_icon.png


+ 185 - 4
src/components/pages/aiAddCourse/addCourse.vue

@@ -125,7 +125,7 @@
                                 border-radius: 5px;
                                 font-weight: 600;
                                 padding: 12px 14px 12px 71px;
-                              " />
+                              "  @change="setCover"/>
                             <el-switch v-model="isTeacherSee" active-text="是否公开此课程"
                               style="justify-content: center; width: 200px"></el-switch>
                           </div>
@@ -172,7 +172,7 @@
                         </div>
                       </div>
                     </div>
-                    <div class="right_first">
+                    <div class="right_first" v-loading="imageloading2">
                       <!-- <div class="ai_box">
                       <div class="ai_content" @click="openAI"><img src="../../../assets/icon/new/ai.png"/><span>AI共创</span></div>
                     </div> -->
@@ -675,12 +675,16 @@
                     </div>
                     <div class="outline_detail" v-loading="taskDetailLoading5.indexOf('task-' + index) !== -1">
                       <textarea v-autoHeight="100" rows="4" class="binfo_input binfo_textarea" cols placeholder="请输入教案"
-                        v-model="item.taskDetail3"></textarea>
+                        v-model="item.taskDetail3" v-if="item.isTask3"></textarea>
+                      <div class="markBox" v-html="MarkdownT(item.taskDetail3)" v-else></div>
                       <div class="op_box">
                         <div class="op_remark">*可以将需要优化的建议添加在任务描述后,点击“智能优化”,自动进行修改</div>
-                        <div class="r_pub_button_op"
+                        <div style="display: flex;">
+                          <div class="r_pub_button_op"
                           @contextmenu.prevent="openAiDialog(1, 'teacherDetail', item.taskDetail3, index)"
                           @click="openAiDialog(2, 'teacherDetail', item.taskDetail3, index)">智能优化</div>
+                          <div class="r_pub_button_edit" style="margin-left:10px" @click="editTask3(index)">{{ item.isTask3 ? '确定' : '编辑'}}</div>
+                        </div>
                       </div>
                     </div>
                   </div>
@@ -5105,6 +5109,7 @@ import aiDialog from './aiDialog'
 import aiTips from './aiTips.vue'
 import tipsDialog from './tipsDialog.vue'
 import { v4 as uuidv4 } from "uuid";
+import MarkdownIt from "markdown-it";
 
 export default {
   components: {
@@ -5207,6 +5212,7 @@ export default {
       oid: this.$route.query.oid,
       org: this.$route.query.org,
       role: this.$route.query.role,
+      aiId: this.$route.query.aiId != undefined ? this.$route.query.aiId : "",
       cid: this.$route.query.cid != undefined ? this.$route.query.cid : "",
       dialogVisibleTable: false,
       dialogVisibleWord: false,
@@ -5360,6 +5366,7 @@ export default {
       isPasteChoice: false,
       imageList: [],
       imageloading: false,
+      imageloading2: false,
       searchImageValue: "",
       ppage: 1,
       toolsData: toolsData,
@@ -5569,6 +5576,13 @@ export default {
         return this.grade.length ? _c2.join("、") : "";
       };
     },
+    MarkdownT() {
+      return function (c) {
+        let md = new MarkdownIt();
+        return c
+          ? md.render(c) : "";
+      };
+    },
   },
   watch: {
     unitIndex(newValue, oldValue) {
@@ -10630,6 +10644,66 @@ export default {
             console.error(err);
           });
       }
+
+      if(this.aiId){
+        let params = {
+          cid: this.aiId,
+        };
+        this.ajax
+          .get(this.$store.state.api + "select_course_detail", params)
+          .then((res) => {
+ 
+            this.$forceUpdate();
+            this.courseName = res.data[0][0].title;
+            this.courseText = res.data[0][0].brief;
+            this.courseText2 = res.data[0][0].reBrief;
+            this.cover = JSON.parse(res.data[0][0].cover);
+            this.noneBtnImg = this.cover.length >= 1;
+            if (res.data[0][0].refile) {
+              this.infoData = JSON.parse(res.data[0][0].refile)
+            }
+
+            this.checkboxList2 = res.data[0][0].juri
+              ? res.data[0][0].juri.split(",")
+              : [];
+            this.inviteCode = [];
+            for (var i = 0; i < res.data[2].length; i++) {
+              this.inviteCode.push({
+                cid: res.data[2][i].classid,
+                ic: res.data[2][i].code,
+              });
+            }
+
+            this.checkboxList3 = res.data[0][0].course_teacher
+              ? res.data[0][0].course_teacher.split(",")
+              : [];
+            this.isTeacherSee = res.data[0][0].open == 1 ? true : false;
+            this.myWord = res.data[0][0].template;
+            this.templateC.id = "123";
+            this.courseTypeId = [];
+            for (var i = 0; i < res.data[1].length; i++) {
+              this.courseTypeId.push(res.data[1][i].typeid);
+            }
+            console.log(this.courseTypeId);
+
+           
+            this.setMan();
+            this.unitJson[
+              this.unitIndex
+            ].chapterInfo[0].taskJson[0].toolOpen = true;
+
+            this.$forceUpdate();
+            setTimeout(() => {
+              this.checkEva(this.evalua);
+              setTimeout(() => {
+                this.checkEva(this.evalua);
+              }, 100);
+            }, 100);
+          })
+          .catch((err) => {
+            console.error(err);
+          });
+      }
       // if(this.cidType != 1 && this.templateid == ''){
       //   this.promptShow = true
       // }
@@ -11998,6 +12072,37 @@ export default {
         this.isPasteTask = true;
       }
     },
+    setCover() {
+      var _this = this;
+      if(_this.cover.length){
+        return;
+      }
+      _this.imageloading2 = true
+      _this.ajax
+        .post("https://gpt.cocorobo.cn/search_image", {
+          page: _this.ppage,
+          pagesize: 9,
+          query: _this.courseName,
+        })
+        .then(function (response) {
+          // console.log(response.data.data);
+          var data = response.data.FunctionResponse.result;
+          _this.cover = [];
+          setTimeout(() => {
+              _this.cover[0] = {
+              name: "网络图片.png",
+              url: data[0].thumbnail
+            };
+            _this.imgChange1(null, null, 1, null);
+            _this.$forceUpdate();
+          }, 0);
+          _this.imageloading2 = false
+        })
+        .catch(function (error) {
+          _this.imageloading2 = false
+          console.log(error);
+        });
+    },
     searchImage() {
       var _this = this;
       _this.imageList = [];
@@ -12458,6 +12563,14 @@ export default {
       this.aiJson[pan] = string
       this.$forceUpdate();
     },
+    editTask3(index){
+      if(this.unitJson[0].chapterInfo[0].taskJson[index].isTask3){
+        this.unitJson[0].chapterInfo[0].taskJson[index].isTask3 = false
+      }else {
+        this.unitJson[0].chapterInfo[0].taskJson[index].isTask3 = true
+      }
+      this.$forceUpdate();
+    },
     openAiDialog(clickType, type, callback, index, tindex) {
       this.clickType = clickType
       let sub = []
@@ -18007,4 +18120,72 @@ ol {
 .text_panel>>>.text {
   height: 400px;
 }
+
+.markBox{
+  padding: 20px 14px;
+  line-height: 29px;
+  font-size: 16px;
+  background: #f4f4f4;
+  border-radius: 5px;
+}
+
+/* table 样式 */
+.markBox >>> table {
+  border-top: 1px solid #ccc;
+  border-left: 1px solid #ccc;
+}
+
+.markBox >>> table td,
+.markBox >>> table th {
+  border-bottom: 1px solid #ccc;
+  border-right: 1px solid #ccc;
+  /* padding: 20px 5px; */
+  padding: 5px 10px;
+  max-width: 0px;
+  height: 30px;
+  vertical-align: baseline;
+  box-sizing: border-box;
+}
+
+.markBox >>> table th {
+  border-bottom: 2px solid #ccc;
+  text-align: center;
+}
+
+/* blockquote 样式 */
+.markBox >>> blockquote {
+  display: block;
+  border-left: 8px solid #d0e5f2;
+  padding: 5px 10px;
+  margin: 10px 0;
+  line-height: 1.4;
+  font-size: 100%;
+  background-color: #f1f1f1;
+}
+
+/* code 样式 */
+.markBox >>> code {
+  display: inline-block;
+  /* *display: inline; */
+  zoom: 1;
+  background-color: #f1f1f1;
+  border-radius: 3px;
+  padding: 3px 5px;
+  margin: 0 3px;
+}
+
+.markBox >>> pre code {
+  display: block;
+}
+
+/* ul ol 样式 */
+.markBox >>> ul,
+ol {
+  margin: 10px 0 10px 20px;
+}
+
+.markBox >>> li,ul{
+  list-style: none;
+
+}
 </style>

+ 2 - 2
src/components/pages/aiAddCourse/templateDialog.vue

@@ -185,8 +185,8 @@ export default {
                     this.searchDataList = res.data[0]
                     if (!this.input2) {
                         this.searchDataList.unshift({
-                            name: "默认模板",
-                            detail: "默认模板",
+                            name: "项目式学习 (Project-Based Learning, PBL)",
+                            detail: "项目式学习是一种以学生为中心的教学方法,通过实际项目和问题解决,培养学生的深度学习和应用能力。",
                             id:''
                         });
                     }

+ 1 - 1
src/components/pages/classroomObservation/components/analysisItem.vue

@@ -229,7 +229,7 @@ export default {
 				);
 				let parm = {
 					assistant_id: assistant?assistant.value:null,
-					message:`请根据文件的类型,使用代码解析器或者文件检索的方式完整的去分析文件内容,并请完全按照要求输出。`,
+					message:`使用文件检索的方式完整的去分析文件内容,并请完全按照要求输出。`,
 					session_name: uuidv4(),
 					userId: this.userId,
 					file_ids: this.fileId?[this.fileId]:'',

+ 18 - 6
src/components/pages/classroomObservation/components/baseMessage.vue

@@ -171,6 +171,7 @@
 								<div
 									class="m-m-fi-imageItem"
 									style="max-width:33%;"
+									v-if="imageList.videoList.length"
 									v-for="(item, index) in imageList.videoList?imageList.videoList:[]"
 									:key="index"
 									@click.stop="previewVideo(item.url)"
@@ -183,14 +184,12 @@
 									></el-image>
 									<span @click.stop="delVideo('videoList')">x</span>
 								</div>
-
+							<el-progress v-if="progressData.uploadVideo && !imageList.videoList.length" class="m_m_fi_progress" :percentage="progressData.value"></el-progress>
 							<div
 								class="m-m-fi-imageItem"
 								@click.stop="addVideo()"
 								style="max-width:33%;"
-								v-if="
-									(imageList.videoList&&imageList.videoList.length<=0) || !imageList.videoList
-								"
+								v-if="(((imageList.videoList&&imageList.videoList.length<=0) || !imageList.videoList) && !progressData.uploadVideo)"
 							>
 								<img
 									src="../../../../assets/icon/classroomObservation/Union.svg"
@@ -284,6 +283,10 @@ export default {
 				{ value: "音乐", label: "音乐" },
 				{ value: "其他", label: "其他" },
 			],
+			progressData:{
+				uploadVideo:false,
+				value:0,
+			}
 		};
 	},
 	methods: {
@@ -361,7 +364,8 @@ export default {
 			input.accept = "video/*";
 			input.click();
 			input.onchange = () => {
-				this.uploadVideoLoading = true;
+				this.progressData.uploadVideo = true;
+				// this.uploadVideoLoading = true;
 				let file = input.files[0];
 				var credentials = {
 					accessKeyId: "AKIATLPEDU37QV5CHLMH",
@@ -390,11 +394,13 @@ export default {
 						queueSize: 2,
 						leavePartsOnError: true,
 					};
+					
 					bucket
 						.upload(params, options)
 						.on("httpUploadProgress", function (evt) {
 							//这里可以写进度条
 							// console.log("Uploaded : " + parseInt((evt.loaded * 80) / evt.total) + '%');
+							_this.progressData.value = parseInt((evt.loaded * 100) / evt.total)
 						})
 						.send(function (err, data) {
 							if (err) {
@@ -407,7 +413,9 @@ export default {
 										url: data.Location,
 								})
 							}
-							_this.uploadVideoLoading = false;
+							_this.progressData.uploadVideo = false;
+							_this.progressData.value = 0;
+							// _this.uploadVideoLoading = false;
 						});
 				}
 			};
@@ -673,4 +681,8 @@ export default {
 	margin-left: 1.5%;
 	height: auto;
 }
+
+.m_m_fi_progress{
+	width: 100%;
+}
 </style>

+ 5 - 2
src/components/pages/classroomObservation/index.vue

@@ -34,7 +34,7 @@
 								<span style="float: left">{{ item.label }}</span>
 								<span
 									class="delSelect"
-									@click.stop="delCourse(item.value)"
+									@click.stop="delCourse(item.id)"
 									style="float: right"
 								></span>
 							</div>
@@ -285,7 +285,7 @@ export default {
 		home() {
 			this.$message.info("主页");
 		},
-		delCourse(_value = this.tid) {
+		delCourse(_value) {
 			this.$confirm("此操作将永久删除该课程, 是否继续?", "提示", {
 				confirmButtonText: "确定",
 				cancelButtonText: "取消",
@@ -312,6 +312,8 @@ export default {
 							type: "success",
 							message: "删除成功!",
 						});
+						// 清空tid
+						this.tid = "";
 						this.getCourseList().then((_) => {
 							if (!this.tid) return;
 							this.getFileIdId();
@@ -379,6 +381,7 @@ export default {
 									? item.jsonData.courseName
 									: `${item.tId}课程`,
 								value: item.tId,
+								id:item.id
 							};
 						});
 						_optionData = _optionData.filter(

+ 88 - 0
src/components/pages/contrastObservation/component/chart.vue

@@ -0,0 +1,88 @@
+<template>
+	<div class="chart" id="charts_canvas" ref="chartRef">
+		
+	</div>
+</template>
+
+<script>
+// const getFile = (url) => {
+// 	return new Promise((resolve, reject) => {
+// 		var credentials = {
+// 			accessKeyId: "AKIATLPEDU37QV5CHLMH",
+// 			secretAccessKey: "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",
+// 		}; //秘钥形式的登录上传
+// 		window.AWS.config.update(credentials);
+// 		window.AWS.config.region = "cn-northwest-1"; //设置区域
+// 		let url2 = url;
+// 		let _url2 = "";
+// 		if (
+// 			url2.indexOf("https://view.officeapps.live.com/op/view.aspx?src=") != -1
+// 		) {
+// 			_url2 = url2.split(
+// 				"https://view.officeapps.live.com/op/view.aspx?src="
+// 			)[1];
+// 		} else {
+// 			_url2 = url2;
+// 		}
+// 		var s3 = new window.AWS.S3({ params: { Bucket: "ccrb" } });
+// 		let name = decodeURIComponent(
+// 			_url2.split("https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/")[1]
+// 		);
+// 		var params = {
+// 			Bucket: "ccrb",
+// 			Key: name,
+// 		};
+// 		s3.getObject(params, function (err, data) {
+// 			if (err) {
+// 				console.log(err, err.stack);
+// 				resolve({ data: 1 });
+// 			} else {
+// 				const fileContent = data.Body.toString("utf-8");
+// 				resolve({ data: fileContent });
+// 			} // sxuccessful response
+// 		});
+// 		// axios({
+// 	});
+// };
+export default {
+	props: {
+		data: {
+			type: Object,
+			default: ()=>{},
+		},
+	},
+	data() {
+		return {
+			chartObj:null,
+			chartData:null,
+		};
+	},
+	watch:{
+		data(){
+			this.getChartData();
+		}
+	},
+	methods: {
+		getChartData() {
+			this.chartObj = this.$echarts.init(
+        this.$refs.chartRef
+      );
+			this.chartObj.setOption(this.data);
+		},
+	},
+	mounted() {
+		this.getChartData();
+		window.addEventListener("resize",()=>{
+			this.chartObj.resize();
+		})
+	},
+};
+</script>
+
+<style scoped>
+.chart {
+	max-width: 100%;
+	width: 100%;
+	height: 100%;
+}
+</style>

+ 1452 - 0
src/components/pages/contrastObservation/index.vue

@@ -0,0 +1,1452 @@
+<template>
+	<div class="contrastObservation" v-loading="loading">
+		<div class="co_card co_aggregateData" v-loading="aggregateLoading">
+			<div class="co_ad_title">
+				<img
+					:src="
+						require('../../../assets/icon/contrastObservation/titleIcon.svg')
+					"
+				/>
+				<span>总数据对比</span>
+			</div>
+			<div class="co_ad_chartArea">
+				<chart :data="aggregateData.chartData" />
+			</div>
+			<div class="co_ad_messageArea" v-html="aggregateData.message"></div>
+		</div>
+		<div class="co_card co_ai_card">
+			<div class="co_c_main" v-loading="aiLoading">
+				<div class="co_c_title">AI观察结果</div>
+				<div
+					class="co_c_m_message"
+					v-for="(item, index) in aiData"
+					:key="index"
+				>
+					<div class="co_c_m_m_title co_ai_title">
+						<el-tooltip
+							class="item"
+							effect="dark"
+							:content="item.description"
+							placement="bottom"
+							popper-class="text_tooltip"
+						>
+							<span>{{ item.title }}</span>
+						</el-tooltip>
+					</div>
+					<div class="score">
+						<span class="titleBlob">评分:</span>{{ item.score }}
+					</div>
+					<div class="message">
+						<span class="titleBlob">结论:</span>{{ item.message }}
+					</div>
+					<div class="basis">
+						<span class="titleBlob">依据:</span>
+						<ol>
+							<li
+								v-for="(item2, index2) in item.basis.length ? item.basis : []"
+								:key="index2"
+							>
+								{{ item2 }}
+							</li>
+						</ol>
+					</div>
+					<!-- <div class="co_c_m_m_text">{{ item.message }}</div> -->
+				</div>
+			</div>
+		</div>
+		<div class="co_card co_teacher_card">
+			<div class="co_c_main" v-loading="teacherLoading">
+				<div class="co_c_title">教师观察结果</div>
+				<div
+					class="co_c_m_message"
+					v-for="(item, index) in teacherData"
+					:key="index"
+				>
+					<div class="co_c_m_m_title co_teacher_title">
+						<el-tooltip
+							class="item"
+							effect="dark"
+							:content="item.description"
+							placement="bottom"
+							popper-class="text_tooltip"
+						>
+							<span>{{ item.title }}</span>
+						</el-tooltip>
+					</div>
+					<div class="score">
+						<span class="titleBlob">评分:</span>{{ item.score }}
+					</div>
+					<div class="message">
+						<span class="titleBlob">结论:</span>{{ item.message }}
+					</div>
+					<div class="basis">
+						<span class="titleBlob">依据:</span>
+						<ol>
+							<li
+								v-for="(item2, index2) in item.basis.length ? item.basis : []"
+								:key="index2"
+							>
+								{{ item2 }}
+							</li>
+						</ol>
+					</div>
+					<!-- <div class="co_c_m_m_text">{{ item.message }}</div> -->
+				</div>
+			</div>
+		</div>
+		<div class="co_card co_contrast_card">
+			<div class="co_c_main" v-loading="contrastLoading">
+				<div class="co_c_title">对比观察结果</div>
+				<div
+					class="co_c_m_message"
+					v-for="(item, index) in contrastData"
+					:key="index"
+				>
+					<div class="co_c_m_m_title co_contrast_title">
+						<el-tooltip
+							class="item"
+							effect="dark"
+							:content="item.description"
+							placement="bottom"
+							popper-class="text_tooltip"
+						>
+							<span>{{ item.title }}</span>
+						</el-tooltip>
+					</div>
+
+					<div class="similarity">
+						<span class="titleBlob compareTitle">相同点:</span>
+						<span>{{ item.similarity }}</span>
+					</div>
+
+					<!-- <div class="compare" v-else>
+						<div class="titleBlob">相同点:</div>
+						<ol>
+							<li
+								v-for="(item2, index2) in item.similarity.length ? item.similarity : []"
+								:key="index2"
+							>
+								{{ item2 }}
+							</li>
+						</ol>
+					</div> -->
+
+					<div class="difference">
+						<span class="titleBlob compareTitle">不同点:</span>
+						<span>{{ item.difference }}</span>
+					</div>
+
+					<!-- <div class="compare" v-else>
+						<div class="titleBlob">不同点:</div>
+						<ol>
+							<li
+								v-for="(item2, index2) in item.difference.length ? item.difference : []"
+								:key="index2"
+							>
+								{{ item2 }}
+							</li>
+						</ol>
+					</div> -->
+					<!--<div class="score">评分:{{ item.score }}分</div>
+					<div class="message">结论:{{ item.message }}</div>
+					<div class="basis">
+						<span>依据:</span>
+						<ol>
+							<li
+								v-for="(item2, index2) in item.basis.length ? item.basis : []"
+								:key="index2"
+							>
+								{{ item2 }}
+							</li>
+						</ol>
+					</div>-->
+					<!-- <div class="co_c_m_m_text">{{ item.message }}</div> -->
+				</div>
+			</div>
+		</div>
+		<div
+			:class="[
+				'refresh',
+				loading ||
+				aggregateLoading ||
+				aiLoading ||
+				teacherLoading ||
+				contrastLoading
+					? 'refreshDisabled'
+					: '',
+			]"
+			@click.stop="refresh()"
+			v-loading="
+				loading ||
+				aggregateLoading ||
+				aiLoading ||
+				teacherLoading ||
+				contrastLoading
+			"
+		>
+			<img
+				:src="require('../../../assets/icon/contrastObservation/refresh.svg')"
+			/>
+		</div>
+	</div>
+</template>
+
+<script>
+import chart from "./component/chart";
+import { v4 as uuidv4 } from "uuid";
+export default {
+	components: {
+		chart,
+	},
+	data() {
+		return {
+			tid: this.$route.query["tid"],
+			testId: {
+				testId: "",
+				checkUrl: "",
+				doUrl: "",
+			},
+			bmData:null,
+			editorBarData: {
+				type: 0,
+				content: "",
+			},
+			testData: null,
+			isDoTestList: [],
+			loading: false,
+			aggregateLoading: false,
+			aiLoading: false,
+			teacherLoading: false,
+			contrastLoading: false,
+			classroomObservationData: [],
+			aggregateData: {
+				message: ``,
+				chartData: {
+					legend: {
+						data: ["AI的观察结果", "教师观察结果"],
+					},
+					radar: {
+						// shape: 'circle',
+						indicator: [
+							{ name: "教学设计", max: 10 },
+							{ name: "教学实施", max: 10 },
+							{ name: "学生参与", max: 10 },
+							{ name: "知识建构", max: 10 },
+							{ name: "课堂氛围", max: 10 },
+							{ name: "教学评价", max: 10 },
+						],
+					},
+					series: [
+						{
+							name: "Budget vs spending",
+							type: "radar",
+							data: [
+								{
+									value: [0, 0, 0, 0, 0, 0],
+									name: "AI的观察结果",
+								},
+								{
+									value: [0, 0, 0, 0, 0, 0],
+									name: "教师观察结果",
+								},
+							],
+						},
+					],
+				},
+			},
+			aiData: [],
+			teacherData: [],
+			contrastData: [],
+		};
+	},
+	methods: {
+		refresh() {
+			if (
+				this.loading ||
+				this.aggregateLoading ||
+				this.aiLoading ||
+				this.teacherLoading ||
+				this.contrastLoading
+			)
+				return;
+			this.getData(true);
+		},
+		// 获取绑定的testId
+		getBindTestId(flag = false) {
+			return new Promise((resolve, reject) => {
+				if (this.loading || !this.tid) return;
+				this.loading = true;
+				let pram = {
+					tid: this.tid,
+					type: "0",
+				};
+				this.ajax
+					.post("https://gpt4.cocorobo.cn/get_classroom_observation_new", pram)
+					.then((res) => {
+						let _result = res.data.FunctionResponse.result;
+						if (_result) {
+							let _jsonData = JSON.parse(_result);
+							let baseMessage = _jsonData[0];
+							baseMessage.jsonData = JSON.parse(baseMessage.jsonData);
+							let _testData = baseMessage.jsonData.testData;
+							this.editorBarData = baseMessage.jsonData.editorBarData;
+							this.bmData = baseMessage;
+							if(!flag){//判断是否是需要生成数据
+								if(baseMessage.jsonData.contrastObservationData){//如果有这个字段则只取里面的数据
+									let _data = baseMessage.jsonData.contrastObservationData;
+									this.aggregateData=_data.aggregateData;
+									this.aiData=_data.aiData;
+									this.teacherData=_data.teacherData;
+									this.contrastData=_data.contrastData;
+									return;
+								}
+							}
+							if (_testData) {
+								this.testId = _testData;
+								resolve();
+							} else {
+								this.$message.error("该观察未绑定表单");
+								return;
+							}
+						}
+					})
+					.catch((e) => {
+						this.$message.error("获取testId失败");
+						console.log(e);
+						return;
+					})
+					.finally(() => {
+						this.loading = false;
+					});
+			});
+		},
+		// 获取绑定的表单数据
+		getBindTestData() {
+			return new Promise((resolve, reject) => {
+				if (!this.testId.testId || !this.tid) return;
+				this.loading = true;
+				this.ajax
+					.get(this.$store.state.api + "getTestWorksNoPage", {
+						cid: this.testId.testId,
+						cn: "",
+					})
+					.then((res) => {
+						if (res.data[0].length != 0) {
+							let _result = res.data[0][0];
+							_result.chapters = JSON.parse(_result.chapters);
+							// _result.cover = JSON.parse(_result.cover);
+							this.testData = _result;
+							resolve();
+						}
+						if (res.data[1].length != 0) {
+							let _doTest = res.data[1];
+							_doTest.forEach((i) => {
+								i.courseJson = JSON.parse(i.courseJson);
+							});
+							this.isDoTestList = _doTest;
+						}
+					})
+					.catch((e) => {
+						this.$message.info("获取表单数据失败");
+						console.log(e);
+						return;
+					})
+					.finally((_) => {
+						this.loading = false;
+					});
+			});
+		},
+		// 获取教师观察结果
+		getTeacherResultData() {
+			return new Promise((resolve, reject) => {
+				if (this.teacherLoading || !this.testData) return;
+				if (!this.testData > 0) return this.$message.error("绑定的表单无数据");
+				this.teacherLoading = true;
+				this.teacherData = [];
+				let _workData = [];
+				this.isDoTestList.forEach((item, index) => {
+					if (index == 0) {
+						item.courseJson.forEach((i) => {
+							if (i.type == 1) {
+								// 选择题
+								if (i.json.type == 1) {
+									// 单选题
+									_workData.push({
+										typeName: "单选题",
+										type: "1-1",
+										title: i.json.title,
+										checkList: i.json.array,
+										answer: i.json.answer[0],
+										userAnswer: [i.json.answer2[0]],
+										score: i.json.score,
+									});
+								} else if (i.json.type == 2) {
+									//多选题
+									_workData.push({
+										typeName: "多选题",
+										type: "1-2",
+										title: i.json.title,
+										checkList: i.json.array,
+										answer: i.json.answer,
+										userAnswer: [i.json.answer2],
+										score: i.json.score,
+									});
+								}
+							} else if (i.type == 7) {
+								//评分
+								_workData.push({
+									typeName: "评分题",
+									type: "7",
+									title: i.json.title,
+									max: i.json.big,
+									min: i.json.small,
+									userAnswer: [i.json.answer2],
+								});
+							} else if (i.type == 3) {
+								//问答题
+								_workData.push({
+									typeName: "问答题",
+									type: "3",
+									title: i.json.title,
+									score: i.json.score,
+									answer: i.json.answer,
+									userAnswer: [i.json.answer2],
+								});
+							} else if (i.type == 5) {
+								//附件上传
+							}
+						});
+					} else {
+						item.courseJson.forEach((i) => {
+							if (i.type == 1) {
+								// 选择题
+								if (i.json.type == 1) {
+									// 单选题
+									let _index = _workData.findIndex((j) => j.type == "1-1");
+									if (_index != -1) {
+										_workData[_index].userAnswer.push(i.json.answer2[0]);
+									}
+								} else if (i.json.type == 2) {
+									//多选题
+									let _index = _workData.findIndex((j) => j.type == "1-2");
+									if (_index != -1) {
+										_workData[_index].userAnswer.push(i.json.answer2);
+									}
+								}
+							} else if (i.type == 7) {
+								//评分
+								let _index = _workData.findIndex((j) => j.type == "7");
+								if (_index != -1) {
+									_workData[_index].userAnswer.push(i.json.answer2);
+								}
+							} else if (i.type == 3) {
+								//问答题
+								let _index = _workData.findIndex((j) => j.type == "3");
+								if (_index != -1) {
+									_workData[_index].userAnswer.push(i.json.answer2);
+								}
+							} else if (i.type == 5) {
+								//附件上传
+							}
+						});
+					}
+				});
+				let _workText = ``;
+				_workData.forEach((i) => {
+					if (i.type == "1-1") {
+						let _checkListText = ``;
+						i.checkList.forEach((i2, index) => {
+							_checkListText += `选项${index + 1}:${i2.option}\n`;
+						});
+						let _userAnswerText = ``;
+						let _newAnswer = [];
+						i.userAnswer.forEach((i2) => {
+							if (typeof i2 === "number") {
+								_newAnswer.push(i2);
+							} else {
+								_newAnswer.push(...i2);
+							}
+						});
+						i.checkList.forEach((item, index) => {
+							_userAnswerText += `选择选项${index + 1}的次数:${
+								_newAnswer.filter((i3) => i3 === index).length
+							}\n`;
+						});
+						_workText += `单选题:\n总分:${i.score}分\n题目:${
+							i.title
+						}\n答案:选项${
+							i.answer + 1
+						}\n选项:\n${_checkListText}${_userAnswerText}\n`;
+					} else if (i.type == "1-2") {
+						let _checkListText = ``;
+						i.checkList.forEach((i2, index) => {
+							_checkListText += `选项${index + 1}:${i2.option}\n`;
+						});
+						let _answerText = ``;
+						i.answer.forEach((i4, index4) => {
+							if (index4 != 0) _answerText += `、`;
+							_answerText += `选项${index4 + 1}`;
+						});
+						let _userAnswerText = ``;
+						let _newAnswer = [];
+						i.userAnswer.forEach((i2) => {
+							if (typeof i2 === "number") {
+								_newAnswer.push(i2);
+							} else {
+								_newAnswer.push(...i2);
+							}
+						});
+						i.checkList.forEach((item, index) => {
+							_userAnswerText += `选择选项${index + 1}的次数:${
+								_newAnswer.filter((i3) => i3 === index).length
+							}\n`;
+						});
+						_workText += `多选题:\n总分:${i.score}分\n题目:${i.title}\n答案:${_answerText}\n选项:\n${_checkListText}${_userAnswerText}\n`;
+					} else if (i.type == "7") {
+						let _userAnswerText = ``;
+						let _groupUserAnswer = [];
+						i.userAnswer.forEach((i2) => {
+							if (!_groupUserAnswer.includes(i2)) {
+								_groupUserAnswer.push(i2);
+							}
+						});
+						_groupUserAnswer.forEach((i3) => {
+							_userAnswerText += `${i3}:${
+								i.userAnswer.filter((i4) => i4 === i3).length
+							}\n`;
+						});
+						_workText += `评分题:\n最大评分:${i.max}\n最小评分:${i.min}\n评分与次数:\n${_userAnswerText}\n\n`;
+					} else if (i.type == "3") {
+						let _userAnswerText = ``;
+						let _groupUserAnswer = [];
+						i.userAnswer.forEach((i2) => {
+							if (!_groupUserAnswer.includes(i2)) {
+								_groupUserAnswer.push(i2);
+							}
+						});
+						_groupUserAnswer.forEach((i3) => {
+							_userAnswerText += `${i3}:${
+								i.userAnswer.filter((i4) => i4 === i3).length
+							}\n`;
+						});
+						_workText += `问答题:\n总分:${i.score}分\n题目:${i.title}\n答案:${i.answer}\n答题与次数:\n${_userAnswerText}\n\n`;
+					}
+				});
+				let _msg = `NOTICE
+Role: 你是专业的教育评估专家,熟悉教学评估的六个维度,了解如何从课堂观察报告中提取关键信息,并进行深入分析。
+Language: Please use the same language as the user requirement, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
+ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
+Instruction: Based on the context, follow "Format example", write content.
+
+# Context
+## 任务
+请你基于以下【课堂观察报告】,请你按照【教学目标与内容编排、教学策略与课堂组织、学生参与和学习体验、知识建构和能力培养、课堂氛围与师生关系、教学评价与反馈改进】这六个维度进行分析、总结,并按指定格式输出内容。
+
+1. 教学目标与内容编排:评估教学目标的明确性、内容的科学性、系统性和前沿性,内容与学生实际生活的联系,以及教学活动、资源的合理编排。
+2. 教学策略与课堂组织:分析教师采用的教学模式、教学方法和策略,组织管理能力,师生互动方式,多媒体技术运用,以及教学设计实施的效果。
+3. 学生参与和学习体验:关注学生在课堂上的参与度、参与深度,包括回答问题、提出疑问、讨论互动、动手实践、探究性学习等,以及学习体验的积极性。
+4. 知识建构和能力培养:分析学生对知识的理解深度,知识内化、迁移应用,参与高阶思维活动的情况,以及培养批判性思维、创新能力、问题解决能力等核心素养的效果。
+5. 课堂氛围与师生关系:包括课堂氛围、师生关系、同伴互助、学习动机激发、心理安全感等软实力因素,以及对学生个体差异的关注和包容。
+6. 教学评价与反馈改进:评估教师对学生学习效果的评价方式及时性,形成性评价、小测验、作业反馈等评价方式的运用,反馈质量对学习的促进作用,并根据评价结果持续改进教学。
+
+## 教师课堂观察报告
+
+### 1. 教学目标与内容编排
+
+> 评估教学目标的明确性、内容的科学性、系统性和前沿性,内容与学生实际生活的联系,以及教学活动、资源的合理编排。
+
+评分:{满分10分(给出具体的分值)}
+结论:{给出具体的评分理由。使用3个完整的句子。}
+依据:{基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。}
+
+### 2. 教学策略与课堂组织
+> 分析教师采用的教学模式、教学方法和策略,组织管理能力,师生互动方式,多媒体技术运用,以及教学设计实施的效果。
+
+评分:
+结论:
+依据:
+
+### 3.
+
+### 4.
+
+### 5.
+
+### 6.
+
+## 数据
+${_workText}
+
+### 课堂实录文稿
+${this.editorBarData.type == 0 ? this.editorBarData.content : ""}
+
+# Format example
+[
+	{
+		"title":"教学目标与内容编排",
+		"description":"评估教学目标的明确性、内容的科学性、系统性和前沿性,内容与学生实际生活的联系,以及教学活动、资源的合理编排。",
+		"score":"参考满分10分(只给出具体的分值)",
+		"message": "给出具体的评分理由。使用3个完整的句子。",
+		"basis":["基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。"]
+	},
+	{
+		"title": "教学策略与课堂组织",
+		"description":"分析教师采用的教学模式、教学方法和策略,组织管理能力,师生互动方式,多媒体技术运用,以及教学设计实施的效果。",
+		"score":"参考满分10分(给出具体的分值)",
+		"message":"给出具体的评分理由。使用3个完整的句子。",
+		"basis":["基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。使用"]
+	},
+	{
+		"title": "学生参与和学习体验",
+		"description":"关注学生在课堂上的参与度、参与深度,包括回答问题、提出疑问、讨论互动、动手实践、探究性学习等,以及学习体验的积极性。",
+		"score":"参考满分10分(给出具体的分值)",
+		"message":"给出具体的评分理由。使用3个完整的句子。",
+		"basis":["基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。使用"]
+	},
+	{
+		"title": "知识建构和能力培养",
+		"description":"分析学生对知识的理解深度,知识内化、迁移应用,参与高阶思维活动的情况,以及培养批判性思维、创新能力、问题解决能力等核心素养的效果。",
+		"score":"参考满分10分(给出具体的分值)",
+		"message":"给出具体的评分理由。使用3个完整的句子。",
+		"basis":["基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。使用"]
+	},
+	{
+		"title": "课堂氛围与师生关系",
+		"description":"包括课堂氛围、师生关系、同伴互助、学习动机激发、心理安全感等软实力因素,以及对学生个体差异的关注和包容。",
+		"score":"参考满分10分(给出具体的分值)",
+		"message":"给出具体的评分理由。使用3个完整的句子。",
+		"basis":["基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。使用"]
+	},
+	{
+		"title": "教学评价与反馈改进",
+		"description":"评估教师对学生学习效果的评价方式及时性,形成性评价、小测验、作业反馈等评价方式的运用,反馈质量对学习的促进作用,并根据评价结果持续改进教学。",
+		"score":"参考满分10分(给出具体的分值)",
+		"message":"给出具体的评分理由。使用3个完整的句子。",
+		"basis":["基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。使用"]
+	},
+]`;
+				// console.log("👇教师观察")
+				// 				console.log(_msg)
+				const _uuid = uuidv4();
+				let params = {
+					model: "gpt-3.5-turbo",
+					temperature: 0,
+					max_tokens: 4096,
+					top_p: 1,
+					frequency_penalty: 0,
+					presence_penalty: 0,
+					messages: [{ role: "user", content: _msg }],
+					uid: _uuid,
+					mind_map_question: "",
+					stream: false,
+				};
+				this.ajax
+					.post("https://gpt4.cocorobo.cn/chat", params)
+					.then((res) => {
+						let _data = res.data.FunctionResponse.choices[0];
+						let _jsonData = _data.message.content;
+						// console.log("👇教师观察👇")
+						// console.log(_jsonData)
+						// console.log("👆教师观察👆")
+						// _jsonData = _jsonData
+						// 	.replaceAll("```json", "")
+						// 	.replaceAll("```", "");
+						// _jsonData.replace(/'/g, '"').replace(/(\w+):/g, '"$1":');
+						let _result = JSON.parse(_jsonData);
+						this.teacherData = _result;
+						resolve();
+					})
+					.catch((e) => {
+						console.log(e);
+						this.$message.error("生成教师观察结果失败");
+					})
+					.finally((_) => {
+						this.teacherLoading = false;
+					});
+			});
+		},
+		//获取观察数据
+		getClassroomObservationData() {
+			return new Promise((resolve, reject) => {
+				let params = {
+					tid: this.tid,
+				};
+				this.loading = true;
+				this.ajax
+					.post("https://gpt4.cocorobo.cn/get_classroom_ob_tid", params)
+					.then((res) => {
+						let _data = res.data.FunctionResponse.result;
+						let _result = JSON.parse(_data);
+						this.classroomObservationData = _result;
+						resolve();
+					});
+			});
+		},
+		// 获取AI观察结果
+		getAiResultData() {
+			return new Promise((resolve, reject) => {
+				if (this.aiLoading || this.loading) return;
+				if (!this.classroomObservationData.length > 0) {
+					return this.getClassroomObservationData().then((_) => {
+						this.getAiResultData().then((_) => {
+							resolve();
+						});
+					});
+				}
+				this.aiLoading = true;
+				this.aiData = [];
+				let _workText = ``; //转换的提示词
+				let _sum = 0;
+				this.classroomObservationData.forEach((i) => {
+					if ([0, 1, 2].includes(i.Type)) {
+						let _jsonObj = JSON.parse(i.jsonData);
+						if (!_jsonObj.courseName) {
+							if (_jsonObj.name !== "课堂记录") {
+								_workText += `名称:${_jsonObj.name}\n分析内容:${_jsonObj.content}\n\n`;
+							}
+						}
+					}
+				});
+				let _msg = `NOTICE
+Role: 你是专业的教育评估专家,熟悉教学评估的六个维度,了解如何从课堂观察报告中提取关键信息,并进行深入分析。
+Language: Please use the same language as the user requirement, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
+ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
+Instruction: Based on the context, follow "Format example", write content.
+
+# Context
+## 任务
+请你基于以下【课堂观察报告】,请你按照【教学目标与内容编排、教学策略与课堂组织、学生参与和学习体验、知识建构和能力培养、课堂氛围与师生关系、教学评价与反馈改进】这六个维度进行分析、总结,并按指定格式输出内容。
+
+1. 教学目标与内容编排:评估教学目标的明确性、内容的科学性、系统性和前沿性,内容与学生实际生活的联系,以及教学活动、资源的合理编排。
+2. 教学策略与课堂组织:分析教师采用的教学模式、教学方法和策略,组织管理能力,师生互动方式,多媒体技术运用,以及教学设计实施的效果。
+3. 学生参与和学习体验:关注学生在课堂上的参与度、参与深度,包括回答问题、提出疑问、讨论互动、动手实践、探究性学习等,以及学习体验的积极性。
+4. 知识建构和能力培养:分析学生对知识的理解深度,知识内化、迁移应用,参与高阶思维活动的情况,以及培养批判性思维、创新能力、问题解决能力等核心素养的效果。
+5. 课堂氛围与师生关系:包括课堂氛围、师生关系、同伴互助、学习动机激发、心理安全感等软实力因素,以及对学生个体差异的关注和包容。
+6. 教学评价与反馈改进:评估教师对学生学习效果的评价方式及时性,形成性评价、小测验、作业反馈等评价方式的运用,反馈质量对学习的促进作用,并根据评价结果持续改进教学。
+
+## AI课堂观察报告
+
+### 1. 教学目标与内容编排
+
+> 评估教学目标的明确性、内容的科学性、系统性和前沿性,内容与学生实际生活的联系,以及教学活动、资源的合理编排。
+
+评分:{满分10分(给出具体的分值)}
+结论:{给出具体的评分理由。使用3个完整的句子。}
+依据:{基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。需要指出具体是哪一个模型以及该模型对应的内容。列举出至少3个依据。}
+
+### 2. 教学策略与课堂组织
+> 分析教师采用的教学模式、教学方法和策略,组织管理能力,师生互动方式,多媒体技术运用,以及教学设计实施的效果。
+
+评分:
+结论:
+依据:
+
+### 3. 
+
+### 4. 
+
+### 5.
+
+### 6.
+
+## 数据
+${_workText}
+
+
+### 课堂实录文稿
+${this.editorBarData.type == 0 ? this.editorBarData.content : ""}
+
+# Format example
+[
+	{
+		"title":"教学目标与内容编排",
+		"description":"评估教学目标的明确性、内容的科学性、系统性和前沿性,内容与学生实际生活的联系,以及教学活动、资源的合理编排。",
+		"score":"参考满分10分(只给出具体的分值)",
+		"message": "给出具体的评分理由。使用3个完整的句子。",
+		"basis":["基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。"]
+	},
+	{
+		"title": "教学策略与课堂组织",
+		"description":"分析教师采用的教学模式、教学方法和策略,组织管理能力,师生互动方式,多媒体技术运用,以及教学设计实施的效果。",
+		"score":"参考满分10分(只给出具体的分值)",
+		"message":"给出具体的评分理由。使用3个完整的句子。",
+		"basis":["基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。使用"]
+	},
+	{
+		"title": "学生参与和学习体验",
+		"description":"关注学生在课堂上的参与度、参与深度,包括回答问题、提出疑问、讨论互动、动手实践、探究性学习等,以及学习体验的积极性。",
+		"score":"参考满分10分(只给出具体的分值)",
+		"message":"给出具体的评分理由。使用3个完整的句子。",
+		"basis":["基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。使用"]
+	},
+	{
+		"title": "知识建构和能力培养",
+		"description":"分析学生对知识的理解深度,知识内化、迁移应用,参与高阶思维活动的情况,以及培养批判性思维、创新能力、问题解决能力等核心素养的效果。",
+		"score":"参考满分10分(只给出具体的分值)",
+		"message":"给出具体的评分理由。使用3个完整的句子。",
+		"basis":["基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。使用"]
+	},
+	{
+		"title": "课堂氛围与师生关系",
+		"description":"包括课堂氛围、师生关系、同伴互助、学习动机激发、心理安全感等软实力因素,以及对学生个体差异的关注和包容。",
+		"score":"参考满分10分(只给出具体的分值)",
+		"message":"给出具体的评分理由。使用3个完整的句子。",
+		"basis":["基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。使用"]
+	},
+	{
+		"title": "教学评价与反馈改进",
+		"description":"评估教师对学生学习效果的评价方式及时性,形成性评价、小测验、作业反馈等评价方式的运用,反馈质量对学习的促进作用,并根据评价结果持续改进教学。",
+		"score":"参考满分10分(只给出具体的分值)",
+		"message":"给出具体的评分理由。使用3个完整的句子。",
+		"basis":["基于【课堂观察报告】中每个模块的分析数据,提供对应的评分依据,也就是支持你结论的数据。列举出至少3个依据。使用"]
+	}
+]`;
+				// console.log("👇AI观察")
+				// console.log(_msg)
+				const _uuid = uuidv4();
+				let params = {
+					model: "gpt-3.5-turbo",
+					temperature: 0,
+					max_tokens: 4096,
+					top_p: 1,
+					frequency_penalty: 0,
+					presence_penalty: 0,
+					messages: [{ role: "user", content: _msg }],
+					uid: _uuid,
+					mind_map_question: "",
+					stream: false,
+				};
+				this.ajax
+					.post("https://gpt4.cocorobo.cn/chat", params)
+					.then((res) => {
+						let _data = res.data.FunctionResponse.choices[0];
+						let _jsonData = _data.message.content;
+						// console.log("👇AI观察👇")
+						// console.log(_jsonData)
+						// console.log("👆AI观察👆")
+						// _jsonData = _jsonData
+						// 	.replaceAll("```json", "")
+						// 	.replaceAll("```", "");
+						// _jsonData.replace(/'/g, '"').replace(/(\w+):/g, '"$1":');
+						let _result = JSON.parse(_jsonData);
+						this.aiData = _result;
+						resolve();
+					})
+					.catch((e) => {
+						console.log(e);
+						this.$message.error("生成ai观察结果失败");
+					})
+					.finally((_) => {
+						this.aiLoading = false;
+					});
+			});
+		},
+		// 获取对比观察
+		getContrastResultData() {
+			return new Promise((resolve, reject) => {
+				if (this.contrastLoading || this.loading) return;
+				if (!this.teacherData.length > 0) {
+					return this.$message.error("缺少教师观察结果");
+				} else if (!this.aiData.length > 0) {
+					return this.$message.error("缺少ai观察结果");
+				}
+				this.contrastLoading = true;
+				this.contrastData = [];
+				let _teacherWorkText = ``; //教师观察转换的提示词
+				let _aiWorkText = ``; //ai观察转换的提示词
+
+				// 转换教师观察结果数据
+				this.teacherData.forEach((i) => {
+					_teacherWorkText += `
+标题:${i.title}
+描述:${i.description}
+评分:${i.score}
+结论:${i.message}
+依据:${i.basis.join("、")}\n
+`;
+				});
+				//转换ai观察结果数据
+				this.aiData.forEach((i) => {
+					_aiWorkText += `
+标题:${i.title}
+描述:${i.description}
+评分:${i.score}
+结论:${i.message}
+依据:${i.basis.join("、")}\n
+`;
+				});
+
+				let _msg = `
+NOTICE
+Language: Please use the same language as the user requirement, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
+
+## 任务
+
+你是专业的教育评估专家,熟悉教学评估的六个维度,了解如何从课堂观察报告中提取关键信息,并进行深入分析。
+
+以下是两份不同的【课堂观察报告】,两个包含均从这六个维度对课堂进行分析,【教学目标与内容编排、教学策略与课堂组织、学生参与和学习体验、知识建构和能力培养、课堂氛围与师生关系、教学评价与反馈改进】这六个维度。请你对两个报告的内容从六个不同维度进行对比分析。
+
+1. 教学目标与内容编排:评估教学目标的明确性、内容的科学性、系统性和前沿性,内容与学生实际生活的联系,以及教学活动、资源的合理编排。
+2. 教学策略与课堂组织:分析教师采用的教学模式、教学方法和策略,组织管理能力,师生互动方式,多媒体技术运用,以及教学设计实施的效果。
+3. 学生参与和学习体验:关注学生在课堂上的参与度、参与深度,包括回答问题、提出疑问、讨论互动、动手实践、探究性学习等,以及学习体验的积极性。
+4. 知识建构和能力培养:分析学生对知识的理解深度,知识内化、迁移应用,参与高阶思维活动的情况,以及培养批判性思维、创新能力、问题解决能力等核心素养的效果。
+5. 课堂氛围与师生关系:包括课堂氛围、师生关系、同伴互助、学习动机激发、心理安全感等软实力因素,以及对学生个体差异的关注和包容。
+6. 教学评价与反馈改进:评估教师对学生学习效果的评价方式及时性,形成性评价、小测验、作业反馈等评价方式的运用,反馈质量对学习的促进作用,并根据评价结果持续改进教学。
+
+## 输出
+
+### 输出要求
+
+### 输出格式
+[
+	{
+		"title":"教学目标与内容编排",
+		"description":"评估教学目标的明确性、内容的科学性、系统性和前沿性,内容与学生实际生活的联系,以及教学活动、资源的合理编排。",
+		"similarity":"使用3句完整的话进行描述",
+		"difference": "使用3句完整的话进行描述"
+	},
+	{
+		"title": "教学策略与课堂组织",
+		"description":"分析教师采用的教学模式、教学方法和策略,组织管理能力,师生互动方式,多媒体技术运用,以及教学设计实施的效果。",
+		"similarity":"使用3句完整的话进行描述",
+		"difference": "使用3句完整的话进行描述"
+	},
+	{
+		"title": "学生参与和学习体验",
+		"description":"关注学生在课堂上的参与度、参与深度,包括回答问题、提出疑问、讨论互动、动手实践、探究性学习等,以及学习体验的积极性。",
+		"similarity":"使用3句完整的话进行描述(最好是数组)",
+		"similarity":"使用3句完整的话进行描述",
+		"difference": "使用3句完整的话进行描述"
+	},
+	{
+		"title": "知识建构和能力培养",
+		"description":"分析学生对知识的理解深度,知识内化、迁移应用,参与高阶思维活动的情况,以及培养批判性思维、创新能力、问题解决能力等核心素养的效果。",
+		"similarity":"使用3句完整的话进行描述",
+		"difference": "使用3句完整的话进行描述"
+	},
+	{
+		"title": "课堂氛围与师生关系",
+		"description":"包括课堂氛围、师生关系、同伴互助、学习动机激发、心理安全感等软实力因素,以及对学生个体差异的关注和包容。",
+		"similarity":"使用3句完整的话进行描述",
+		"difference": "使用3句完整的话进行描述"
+	},
+	{
+		"title": "教学评价与反馈改进",
+		"description":"评估教师对学生学习效果的评价方式及时性,形成性评价、小测验、作业反馈等评价方式的运用,反馈质量对学习的促进作用,并根据评价结果持续改进教学。",
+		"similarity":"使用3句完整的话进行描述",
+		"difference": "使用3句完整的话进行描述"
+	}
+]
+### 1. 教学目标与内容编排
+
+> 评估教学目标的明确性、内容的科学性、系统性和前沿性,内容与学生实际生活的联系,以及教学活动、资源的合理编排。
+
+相同点:{使用3句完整的话进行描述}
+不同点:{使用3句完整的话进行描述}
+
+### 2. 教学策略与课堂组织
+> 分析教师采用的教学模式、教学方法和策略,组织管理能力,师生互动方式,多媒体技术运用,以及教学设计实施的效果。
+
+
+### 3. 
+
+### 4. 
+
+### 5.
+
+### 6.
+
+## 数据
+
+### 教师课堂观察报告 
+${_teacherWorkText}
+
+
+### AI课堂观察报告
+${_aiWorkText}
+
+
+`;
+				// this.contrastLoading = false;
+				// console.log("对比观察提示词👇👇")
+				// console.log(_msg)
+				// return;
+				const _uuid = uuidv4();
+				let params = {
+					model: "gpt-3.5-turbo",
+					temperature: 0,
+					max_tokens: 4096,
+					top_p: 1,
+					frequency_penalty: 0,
+					presence_penalty: 0,
+					messages: [{ role: "user", content: _msg }],
+					uid: _uuid,
+					mind_map_question: "",
+					stream: false,
+				};
+				this.ajax
+					.post("https://gpt4.cocorobo.cn/chat", params)
+					.then((res) => {
+						let _data = res.data.FunctionResponse.choices[0];
+						let _jsonData = _data.message.content;
+						_jsonData = _jsonData
+							.replaceAll("```json", "")
+							.replaceAll("```", "");
+						let _result = JSON.parse(_jsonData);
+
+						this.contrastData = _result;
+						resolve();
+					})
+					.catch((e) => {
+						console.log(e);
+						this.$message.error("生成对比观察结果失败");
+					})
+					.finally((_) => {
+						this.contrastLoading = false;
+					});
+			});
+		},
+		// 获取总数据对比
+		getAggregateResultData() {
+			return new Promise((resolve, reject) => {
+				if (!this.aiData.length > 0) {
+					return this.$message.info("请先获取ai观察结果");
+				} else if (!this.teacherData.length > 0) {
+					return this.$message.error("请先获取教师观察结果");
+				}
+				this.aggregateLoading = true;
+				this.aggregateData.message = "";
+				let _teacherWorkText = ``; //教师观察转换的提示词
+				let _aiWorkText = ``; //ai观察转换的提示词
+
+				// 转换教师观察结果数据
+				this.teacherData.forEach((i) => {
+					_teacherWorkText += `
+标题:${i.title}
+描述:${i.description}
+评分:${i.score}
+结论:${i.message}
+依据:${i.basis.join("、")}\n
+`;
+				});
+				//转换ai观察结果数据
+				this.aiData.forEach((i) => {
+					_aiWorkText += `
+标题:${i.title}
+描述:${i.description}
+评分:${i.score}
+结论:${i.message}
+依据:${i.basis.join("、")}\n
+`;
+				});
+				let _msg = `
+NOTICE
+Language: Please use the same language as the user requirement, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
+
+## 任务
+
+你是专业的教育评估专家,熟悉教学评估的六个维度,了解如何从课堂观察报告中提取关键信息,并进行深入分析。
+
+以下是两份不同的【课堂观察报告】,两个包含均从这六个维度对课堂进行分析,【教学目标与内容编排、教学策略与课堂组织、学生参与和学习体验、知识建构和能力培养、课堂氛围与师生关系、教学评价与反馈改进】这六个维度。请你对两个报告的内容进行对比分析,指出其中的相同点和不同点。仅仅输出一段完整的小论文进行介绍,使用不超过10句完整的话,需适当指出各自的得分情况。
+
+1. 教学目标与内容编排:评估教学目标的明确性、内容的科学性、系统性和前沿性,内容与学生实际生活的联系,以及教学活动、资源的合理编排。
+2. 教学策略与课堂组织:分析教师采用的教学模式、教学方法和策略,组织管理能力,师生互动方式,多媒体技术运用,以及教学设计实施的效果。
+3. 学生参与和学习体验:关注学生在课堂上的参与度、参与深度,包括回答问题、提出疑问、讨论互动、动手实践、探究性学习等,以及学习体验的积极性。
+4. 知识建构和能力培养:分析学生对知识的理解深度,知识内化、迁移应用,参与高阶思维活动的情况,以及培养批判性思维、创新能力、问题解决能力等核心素养的效果。
+5. 课堂氛围与师生关系:包括课堂氛围、师生关系、同伴互助、学习动机激发、心理安全感等软实力因素,以及对学生个体差异的关注和包容。
+6. 教学评价与反馈改进:评估教师对学生学习效果的评价方式及时性,形成性评价、小测验、作业反馈等评价方式的运用,反馈质量对学习的促进作用,并根据评价结果持续改进教学。
+
+## 输出
+
+### 输出要求
+
+### 输出格式
+
+{仅仅输出一段完整的小论文进行介绍,使用不超过10句完整的话,需适当指出各自的得分情况。最好是字符串}
+
+
+## 数据
+
+### 教师课堂观察报告 
+${_teacherWorkText}
+
+### AI课堂观察报告
+${_aiWorkText}
+			
+`;
+				// console.log("总数居对比");
+				// console.log(_msg)
+				// return this.aggregateLoading = false;
+				const _uuid = uuidv4();
+				let params = {
+					model: "gpt-3.5-turbo",
+					temperature: 0,
+					max_tokens: 4096,
+					top_p: 1,
+					frequency_penalty: 0,
+					presence_penalty: 0,
+					messages: [{ role: "user", content: _msg }],
+					uid: _uuid,
+					mind_map_question: "",
+					stream: false,
+				};
+				this.ajax
+					.post("https://gpt4.cocorobo.cn/chat", params)
+					.then((res) => {
+						let _data = res.data.FunctionResponse.choices[0];
+						let _result = _data.message.content;
+						this.aggregateData.message = _result;
+						resolve();
+						// let _jsonData = _data.message.content;
+						// _jsonData = _jsonData.replaceAll("```json", "").replaceAll("```", "");
+						// let _result = JSON.parse(_jsonData);
+						// this.aiData = _result;
+					})
+					.catch((e) => {
+						console.log(e);
+						this.$message.error("生成总结数据对比失败");
+					})
+					.finally((_) => {
+						this.aggregateLoading = false;
+					});
+			});
+		},
+		// 计算总数据对比里的雷达图
+		getAggregateChartData() {
+			if (!this.aiData.length > 0) {
+				return this.$message.info("请先获取ai观察结果");
+			} else if (!this.teacherData.length > 0) {
+				return this.$message.error("请先获取教师观察结果");
+			}
+			let _teacherData = {
+				value: [],
+				name: "教师观察结果",
+			};
+			let _aiData = {
+				value: [],
+				name: "AI的观察结果",
+			};
+
+			let _chartData = JSON.parse(JSON.stringify(this.aggregateData.chartData));
+			let _titleList = {
+				教学目标与内容编排: 0,
+				教学策略与课堂组织: 1,
+				学生参与和学习体验: 2,
+				知识建构和能力培养: 3,
+				课堂氛围与师生关系: 4,
+				教学评价与反馈改进: 5,
+			};
+
+			this.teacherData.forEach((i) => {
+				if (i.title in _titleList) {
+					let _scoreStr = i.score;
+					_scoreStr = parseInt(_scoreStr.replaceAll("分", ""));
+					_teacherData.value[_titleList[i.title]] = parseInt(_scoreStr);
+				}
+			});
+			this.aiData.forEach((i) => {
+				if (i.title in _titleList) {
+					let _scoreStr = i.score;
+					_scoreStr = parseInt(_scoreStr.replaceAll("分", ""));
+					_aiData.value[_titleList[i.title]] = parseInt(_scoreStr);
+				}
+			});
+			_chartData.series[0].data = [_aiData, _teacherData];
+			this.aggregateData.chartData = _chartData;
+		},
+		//获取
+		getData(flag = false) {
+			// 获取观察所绑定的表单
+			this.getBindTestId(flag).then((_) => {
+				// 后去表单的数据
+				this.getBindTestData().then((_) => {
+						Promise.all([
+							this.getTeacherResultData(),
+							this.getAiResultData(),
+						]).then((_) => {
+							this.getAggregateChartData();
+							Promise.all([this.getContrastResultData(),this.getAggregateResultData()]).then(_=>{
+								this.saveData()
+							})
+						});
+					});
+			});
+		},
+		//储存数据
+		saveData() {
+			return new Promise((resolve, reject) => {
+				let _saveData = JSON.parse(JSON.stringify(this.bmData));
+				_saveData.jsonData.contrastObservationData = {
+						aggregateData: this.aggregateData,
+						aiData: this.aiData,
+						teacherData: this.teacherData,
+						contrastData: this.contrastData,
+				}
+				let params = {
+					id: _saveData.id,
+					json_data: JSON.stringify(_saveData.jsonData),
+				};
+				// console.log(params)
+				// return resolve();
+				this.ajax
+					.post(
+						"https://gpt4.cocorobo.cn/update_classroom_observation",
+						params
+					)
+					.then((res) => {
+						this.$message.success("保存数据成功")
+						resolve();
+					}).catch(e=>{
+						console.log(e);
+						this.$message.info('保存数据失败')
+					});
+			});
+		},
+	},
+	mounted() {
+		this.getData();
+	},
+};
+</script>
+
+<style scoped>
+.contrastObservation {
+	min-width: 1500px;
+	/* min-height: 800px; */
+	width: 100%;
+	height: 100vh;
+	display: flex;
+	background-color: #f0f2f5;
+	box-sizing: border-box;
+	padding: 30px 20px;
+	background-image: #d4d8f6;
+	display: flex;
+	justify-content: space-around;
+	align-items: center;
+	position: relative;
+}
+
+.refresh {
+	position: fixed;
+	right: 0;
+	top: 40px;
+	width: 60px;
+	height: 60px;
+	background-color: #fff;
+	border-radius: 12px 0px 0px 12px;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	box-shadow: 0 16px 24px 2px #0000000a;
+	cursor: pointer;
+}
+
+.refreshDisabled {
+	cursor: not-allowed;
+}
+
+.co_card_area {
+	width: 100%;
+	height: 100%;
+	display: flex;
+	justify-content: space-around;
+	align-items: center;
+}
+
+.co_card {
+	min-width: 24%;
+	max-width: 24%;
+	width: 23%;
+	height: 100%;
+	box-sizing: border-box;
+	border-radius: 12px;
+	background-color: #fff;
+	box-sizing: border-box;
+	padding: 20px;
+	position: relative;
+	overflow: hidden;
+}
+
+.co_aggregateData {
+	background-color: #fbfcfe;
+	display: flex;
+	flex-direction: column;
+	justify-content: space-between;
+}
+
+.co_ad_title {
+	height: 35px;
+	font-size: 22px;
+	color: #434e69;
+	font-weight: 600;
+	display: flex;
+	align-items: center;
+	margin-bottom: 20px;
+}
+
+.co_ad_title > img {
+	width: 25px;
+	height: 25px;
+	margin-right: 10px;
+}
+
+.co_ad_chartArea {
+	width: 100%;
+	height: 45%;
+	max-height: 45%;
+	margin-bottom: 20px;
+}
+
+.co_ad_messageArea {
+	width: 100%;
+	height: calc(100% - 35px - 45% - 40px);
+	background-color: #eef2fc;
+	box-sizing: border-box;
+	padding: 20px;
+	overflow-y: auto;
+	border: solid 1px #e0eafb;
+	border-radius: 6px;
+	white-space: pre-line;
+	font-size: 18px;
+}
+
+.co_ai_card {
+	padding: 8px 0 0 0;
+	background: linear-gradient(to right, #3673e8, #ad88fd);
+	/* background: linear-gradient(#f4eefd, #fff, #fff, #fff, #fff, #fff); */
+	/* height: calc(100% - 10px); */
+}
+
+.co_ai_card > .co_c_main {
+	background: linear-gradient(#f4eefd, #fff, #fff, #fff, #fff, #fff);
+}
+
+.co_teacher_card {
+	padding: 8px 0 0 0;
+	background: linear-gradient(to right, #3673e8, #88fdc5);
+	/* background: linear-gradient(#f5fffa, #fff, #fff, #fff, #fff, #fff); */
+	/* height: calc(100% - 10px); */
+}
+
+.co_teacher_card > .co_c_main {
+	background: linear-gradient(#f5fffa, #fff, #fff, #fff, #fff, #fff);
+}
+
+.co_contrast_card {
+	padding: 8px 0 0 0;
+	background: linear-gradient(to right, #fdcd72, #fd8888);
+	/* background: linear-gradient(#fffaee, #fff, #fff, #fff, #fff, #fff); */
+	/* height: calc(100% - 10px); */
+}
+
+.co_contrast_card > .co_c_main {
+	background: linear-gradient(#fffaee, #fff, #fff, #fff, #fff, #fff);
+}
+
+.co_c_main {
+	width: calc(100%);
+	height: calc(100%);
+	padding: 20px;
+	box-sizing: border-box;
+	border-radius: 12px;
+	overflow-x: hidden;
+}
+
+.co_c_title {
+	width: calc(100% + 20px);
+	height: 80px;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	position: relative;
+	left: -20px;
+	top: -20px;
+	font-size: 24px;
+	box-sizing: border-box;
+}
+
+.co_c_m_message {
+	width: 100%;
+	height: auto;
+	margin-bottom: 20px;
+}
+
+.co_c_m_m_title {
+	width: 100%;
+	height: 50px;
+	display: flex;
+	align-items: center;
+	font-size: 22px;
+	font-weight: bold;
+	position: relative;
+}
+
+.co_c_m_m_title > span {
+	position: relative;
+	transition: 0.3s;
+}
+
+.co_c_m_m_title > span:hover {
+	color: #3681fc;
+	cursor: help;
+}
+
+.co_c_m_m_title > span::before {
+	content: "";
+	width: 100%;
+	height: 10px;
+	position: absolute;
+	bottom: 0;
+	left: 0;
+	opacity: 0.5;
+}
+
+.co_ai_title > span::before {
+	background: linear-gradient(to right, #3673e8, #ad88fd);
+}
+
+.co_teacher_title > span::before {
+	background: linear-gradient(to right, #3673e8, #88fdc5);
+}
+
+.co_contrast_title > span::before {
+	background: linear-gradient(to right, #fdcd72, #fd8888);
+}
+
+.message,
+.score,
+.basis {
+	font-size: 18px;
+}
+
+.basis > ol {
+	margin-left: 30px;
+}
+
+.compare > ol {
+	margin-left: 30px;
+}
+
+.similarity,
+.difference,
+.compare {
+	font-size: 18px;
+	margin-bottom: 10px;
+}
+.titleBlob {
+	font-weight: bold;
+}
+
+/* .compareTitle{
+	margin-left: 10px;
+	position: relative;
+	display: inline-block;
+}
+
+.compareTitle::after{
+	content: "";
+	width: 20px;
+	height: 20px;
+	position: relative;
+} */
+</style>

+ 19 - 1
src/components/pages/course.vue

@@ -220,6 +220,11 @@
 									<img style="height: 90%;width: 90%;" src="../../assets/icon/course/lookeye.svg">
 								</div>
     					</el-tooltip>
+							<el-tooltip effect="dark" content="Ai一下" placement="top">
+    					  <div class="t_b_Item" @click="aiCourse(item.courseId)">
+									<img src="../../assets/icon/course/aiEdit.svg">
+								</div>
+    					</el-tooltip>
 
 							<el-tooltip effect="dark" content="复制" placement="top">
     					  <div class="t_b_Item" @click="copyCourse(item.courseId)">
@@ -271,7 +276,6 @@
 									<img src="../../assets/icon/course/share.svg">
 								</div>
     					</el-tooltip>
-
 							<!-- v-if="role == '1'" -->
               <!-- <div @click="get(item)">预览</div> -->
               <!-- <div @click="jump(item.courseId)" v-else>评课</div> -->
@@ -634,6 +638,20 @@ export default {
       }
       // this.$router.push(path);
     },
+    aiCourse(courseId){
+      this.$router.push(
+          "/aiAddCourse?userid=" +
+          this.userid +
+          "&oid=" +
+          this.oid +
+          "&org=" +
+          this.org +
+          "&role=" +
+          this.role +
+          "&aiId=" +
+          courseId
+        );
+    },
     reset() {
       this.typeE = []
       this.typea = ''

+ 124 - 0
src/components/pages/pblCourse/component/bars.vue

@@ -0,0 +1,124 @@
+<template>
+  <div class="barCss">
+    <div class="progress">
+      <div ref="bar" class="bar shadow hui"></div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    doIndex: {
+      type: Number,
+      default: 0
+    }
+  },
+  data() {
+    return {};
+  },
+  methods: {
+    getup() {
+      //   const bars = document.querySelectorAll(".bar");
+      const randomWidth = this.doIndex * 20;
+
+      const bars = this.$refs.bar;
+      const progress = document.querySelectorAll(".progress");
+      bars.style.width = `${randomWidth}%`;
+
+      //   bars.forEach((bar, index) => {
+      //     const randomWidth = this.doIndex * 20;
+
+      //     bar.style.width = `${randomWidth}%`;
+
+      //     // progress[index].addEventListener("mouseover", () => {
+      //     //   const randomTiming = Math.floor(Math.random() * 2 + 2);
+      //     //   console.log(randomTiming);
+      //     //   bar.style.transitionDuration = `${randomTiming}s`;
+      //     //   bar.style.width = "100%";
+      //     // });
+      //   });
+    }
+  },
+  mounted() {
+    this.getup();
+  }
+};
+</script>
+
+<style scoped>
+/* @import url("https://fonts.googleapis.com/css?family=Bitter"); */
+
+/* * {
+    border: 1px solid red;
+} */
+:root {
+  --font: "Bitter", serif;
+  --title-size: 36px;
+  --sub-size: 18px;
+}
+
+body {
+  background: #e5e5e5;
+}
+
+.barCss {
+  display: flex;
+  align-items: center;
+}
+.title h1 {
+  margin: 4px;
+  font-family: var(--font);
+  font-size: var(--title-size);
+  color: #333;
+}
+
+.title p {
+  margin: 4px;
+  padding-bottom: 25px;
+  font-family: var(--font);
+  font-size: var(--sub-size);
+  color: #888;
+}
+
+.container {
+  text-align: center;
+}
+
+.progress {
+  display: inline-block;
+  width: 100%;
+  height: 13px;
+  border-radius: 20px;
+  background: #f9f9f9;
+  border: 1px #000 solid;
+}
+
+.bar {
+  border-radius: 20px;
+  width: 0%;
+  height: 100%;
+  transition: width;
+  transition-duration: 1s;
+  transition-timing-function: cubic-bezier(0.36, 0.55, 0.63, 0.48);
+}
+
+.mobile {
+  display: none;
+}
+
+.shadow {
+  /* 25 50 */
+  box-shadow: 0px 45px 50px rgba(0, 0, 0, 0.25);
+}
+
+.hui {
+  background-color: #ccc;
+  background-image: url("../../../../assets/icon/pblCourse/DiagonalLine.png");
+}
+
+.stripes {
+  background-color: #ffffff;
+  background-image: url("data:image/svg+xml,%3Csvg width='25' height='1' viewBox='0 0 40 1' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h20v1H0z' fill='%23d09af3' fill-opacity='0.54' fill-rule='evenodd'/%3E%3C/svg%3E");
+}
+</style>

+ 3 - 2
src/components/pages/pblCourse/component/chatArea.vue

@@ -118,6 +118,7 @@ export default {
 			loading: false,
 			chatLoading:false,
 			userId:this.$route.query['userid'],
+			cid: this.$route.query.cid,
 			chatList: [],
 			textValue: "",
 		};
@@ -269,7 +270,7 @@ export default {
 				alltext: _data.aiContent,
 				type: "chat",
 				filename: _data.filename,
-				session_name: `${this.userId}-pblCourse`,
+				session_name: `${this.userId}-${this.cid}-pblCourse`,
 			};
 			this.ajax
 				.post("https://gpt4.cocorobo.cn/insert_chat", params)
@@ -287,7 +288,7 @@ export default {
 					userid: this.userId,
 					groupid: "602def61-005d-11ee-91d8-005056b8q12w",
 					// session_name:``
-					session_name: `${this.userId}-pblCourse`,
+					session_name: `${this.userId}-${this.cid}-pblCourse`,
 				};
 				this.ajax
 					.post("https://gpt4.cocorobo.cn/get_agent_park_chat", params)

+ 22 - 10
src/components/pages/pblCourse/component/doWorkArea.vue

@@ -11,24 +11,24 @@
 			</div>
 		</div>
 		<div class="dw_work">
-			<work v-if="task" :task="task" @submitTask="down" @choiceAnswer="choiceAnswer" @getTaskList="getTaskList" :phase="phase"/>
+			<work v-if="task" :task="task" @submitTask="down" @choiceAnswer="choiceAnswer" @getTaskList="getTaskList" :phase="phase" @lookFile="lookFile" @deleteFile="deleteFile" @addFile="addFile"/>
 			<div v-else>
 				<h3>等待生成数据...</h3>
 			</div>
 		</div>
-		<div class="dw_bottom">
+		<!-- <div class="dw_bottom">
 			<div class="dw_b_btn" @click.stop="submitTask()">
 				<img :src="require('../../../../assets/icon/pblCourse/bookIcon.png')">
 				<span>提交作业</span>
 			</div>
-		</div>	
+		</div>	 -->
 	</div>
 </template>
 
 <script>
 import work from './work'
 	export default {
-		emits:["changePhase","choiceAnswer","submitTask","getTaskList"],
+		emits:["changePhase","choiceAnswer","submitTask","getTaskList","deleteFile","addFile","lookFile"],
 		props:{
 			phase:{
 				type:Object,
@@ -70,7 +70,16 @@ import work from './work'
 			},
 			getTaskList(_data){
 				this.$emit("getTaskList",_data)
-			}
+			},
+			deleteFile(index){
+				this.$emit("deleteFile",index)
+			},
+			lookFile(index){
+				this.$emit("lookFile",index)
+			},
+			addFile(obj){
+				this.$emit("addFile",obj)
+			},
 		}
 	}
 </script>
@@ -109,7 +118,7 @@ import work from './work'
 
 
 .dw_h_left>span{
-	font-size: 22px;
+	font-size: 24px;
 	font-weight: bold;
 }
 
@@ -134,12 +143,15 @@ import work from './work'
 	transform: rotate(180deg);
 }
 .dw_work{
-	width: calc(100% - 30px);
-	height: calc(100% - 60px - 100px - 30px);
+	width: 100%;
+	/* height: auto; */
+	height: calc(100% - 60px - 30px);
 	box-sizing: border-box;
-	margin: 0 15px;
+	/* margin: 0 15px; */
+	padding: 0 15px;
 	border-radius: 8px;
-	background-color: #F3F7FD;
+	overflow: auto;
+	/* background-color: #F3F7FD; */
 }
 
 .dw_bottom{

+ 1 - 1
src/components/pages/pblCourse/component/procedureArea.vue

@@ -125,7 +125,7 @@
 }
 
 .content .procedure_content.active > .name{
-	border: none;
+	/* border: none;  */
     background: linear-gradient(90deg, #3673E8 0%, #AD88FD 100%);
 }
 

+ 1 - 1
src/components/pages/pblCourse/component/selectTopicDialog.vue

@@ -9,7 +9,7 @@
 			:close-on-press-escape="false"
       v-loading="loading"
     >
-      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px" @submit.native.prevent="() => submitFrom('form')">
         <el-form-item label="选题:" prop="title">
           <el-input v-model="form.title"></el-input>
         </el-form-item>

+ 252 - 0
src/components/pages/pblCourse/component/vpdf.vue

@@ -0,0 +1,252 @@
+<template>
+  <!--使用 pdfvuer 实现 滑动浏览 单印章-->
+  <div class="pdf">
+    <div class="loading" v-show="isloading">
+      <span>pdf可能会加载时间有点长,请耐心等待...</span>
+    </div>
+    <!-- <div id="contentArea" class="show" v-if="!loading">
+      <pdf :scale.sync="scale" :resize="true" ref="wrapper" class="p-pdf" :src="pdfData" v-for="i in numPages" :key="i"
+        :id="i" :page="i" style="width: 100%">
+      </pdf>
+    </div> -->
+    <iframe ref="viframe" style="width: 100%; height: 99%; border: none"
+      :src="'https://cloud.cocorobo.cn/pdf.js/web/viewer.html?file=' + pdfUrl"></iframe>
+    <!-- <div class="rightArea">
+      <div class="toolGroup">
+        <div class="page">第 {{ page }} / {{ numPages }} 页</div>
+        <el-button type="primary" @click.stop="prePage">上一页</el-button>
+        <el-button type="primary" @click.stop="nextPage">下一页</el-button>
+      </div>
+    </div> -->
+  </div>
+</template>
+
+<script>
+// import pdfvuer from "pdfvuer"; // pdfvuer 版本为@1.6.1
+// import "pdfjs-dist/build/pdf.worker.entry";
+// const PDF = require("pdfjs-dist");
+// PDF.GlobalWorkerOptions.workerSrc = "../../common/pdf.worker.js";
+
+export default {
+  name: "Pdfvuer",
+  components: {
+    // pdf: pdfvuer,
+  },
+  props: {
+    // 当前pdf路径
+    pdfUrl: {
+      type: String,
+      default:
+        "https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/0629%E5%AE%9E%E6%97%B6%E8%AF%BE%E5%A0%82%E6%A8%A1%E6%8B%9F%E6%BC%94%E7%A4%BA%E8%AF%BE%E4%BB%B61656920880446.pdf",
+    },
+    ppage: {
+      type: Number,
+      default: 1,
+    },
+  },
+  data() {
+    return {
+      page: 1, // 当前页
+      numPages: 0, // 总页数
+      pdfData: undefined,
+      inputPage: 1, // 输入的页码
+      isloading: false,
+      scale: "page-width",
+    };
+  },
+  mounted() {
+    // this.isloading = this.$loading.service({
+    //   background: "rgba(255, 255, 255, 0.7)",
+    //   target: document.querySelector(".loading"),
+    //   text: "加载中...",
+    //   spinner: "",
+    // });
+    this.isloading = false;
+    this.$refs.viframe.onload = function () {
+      this.isloading = false
+    }
+    console.log(this.isloading);
+    // this.getPdf();
+  },
+  beforeDestroy() { },
+  watch: {
+    pdfUrl: function (s) {
+      // this.isloading = this.$loading.service({
+      //   background: "rgba(255, 255, 255, 0.7)",
+      //   target: document.querySelector(".loading"),
+      //   text: "加载中...",
+      //   spinner: "",
+      // });
+      this.isloading = false;
+      this.$refs.viframe.onload = function () {
+        this.isloading = false
+      }
+      // this.getPdf();
+    },
+  },
+  methods: {
+    // 获取 pdf 信息
+    getPdf() {
+      this.pdfData = pdfvuer.createLoadingTask({
+        url: this.pdfUrl,
+        cMapUrl: "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.16.105/cmaps/",
+        cMapPacked: true,
+      });
+      this.pdfData
+        .then((pdf) => {
+          // this.isloading.close();
+          this.isloading = false
+          this.numPages = pdf.numPages;
+        })
+        .catch((err) => {
+          console.log(err);
+        });
+    },
+    // 上一页
+    prePage() {
+      let page = this.page;
+      page = page > 1 ? page - 1 : 1;
+      this.page = page;
+    },
+    // 下一页
+    nextPage() {
+      let page = this.page;
+      page = page < this.numPages ? page + 1 : this.numPages;
+      this.page = page;
+    },
+  },
+};
+</script>
+<style scoped>
+.loading {
+  height: 100%;
+  width: 100%;
+  /* background: #000; */
+  position: absolute;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  /* background-color: rgba(255, 255, 255, 0.7); */
+  background-color: rgba(255, 255, 255, 1);
+  z-index: 9;
+  font-size: 20px;
+  color: #007fff;
+}
+
+.pdf {
+  height: 100%;
+  width: 100%;
+  position: relative;
+  box-sizing: border-box;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+.pdf .show {
+  margin: auto;
+  width: 100%;
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.pdf .show .p-pdf {
+  overflow: hidden;
+}
+
+.pdf .show .p-pdf .line {
+  position: absolute;
+  width: 50px;
+  right: -50px;
+  background: rgb(255, 186, 96);
+  height: 2px;
+}
+
+.pdf .show .p-pdf span {
+  width: 100%;
+  text-align: center;
+  color: #fff;
+}
+
+.pdf .show .p-pdf span+span {
+  margin-top: 10px;
+}
+
+.pdfbox {
+  /* border: 3px solid #000; */
+  /* box-sizing: border-box; */
+  /* border-radius: 4px; */
+  /* overflow: hidden; */
+}
+
+.pdf .pdf_footer {
+  position: sticky;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  padding: 10px 0;
+  width: 100%;
+  height: 75px;
+  background-color: rgba(255, 255, 255, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-direction: column;
+}
+
+.pdf .pdf_footer .info {
+  display: flex;
+  flex-wrap: wrap;
+  width: 100%;
+  justify-content: center;
+}
+
+.pdf .p-pdf .viewerContainer {
+  width: 100%;
+}
+
+/* .pdf .pdf_footer .info div {
+  width: 30%;
+} */
+.pdf .pdf_footer .operate {
+  margin: 10px 0 0;
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: center;
+  width: 100%;
+}
+
+.pdf .pdf_footer .operate div {
+  text-align: center;
+  font-size: 15px;
+}
+
+.pdf .pdf_footer .operate .btn {
+  cursor: pointer;
+  margin: 5px 10px;
+  width: 100px;
+  border-radius: 10px;
+  padding: 5px;
+  color: #fff;
+  background-color: #066ebe;
+}
+
+.pdf::-webkit-scrollbar {
+  /*滚动条整体样式*/
+  width: 6px;
+  /*高宽分别对应横竖滚动条的尺寸*/
+  height: 6px;
+}
+
+/*定义滚动条轨道 内阴影+圆角*/
+.pdf::-webkit-scrollbar {
+  border-radius: 10px;
+  background-color: #b8bdc9;
+}
+
+/*定义滑块 内阴影+圆角*/
+.pdf::-webkit-scrollbar-thumb {
+  border-radius: 10px;
+  -webkit-box-shadow: inset 0 0 6px rgb(96, 125, 184);
+  background-color: #2c5ab3;
+}
+</style>

+ 621 - 258
src/components/pages/pblCourse/component/work.vue

@@ -1,335 +1,698 @@
 <template>
-	<div class="work" ref="workRef">
-		<div class="w_nowWork">
-			<div class="w_nw_header">
-				<div class="w_nw_h_title">
-					<img :src="require('../../../../assets/icon/pblCourse/taskIcon.png')">  
-					<span>当前任务</span>
-				</div>
-				<div class="w_nw_h_btn" @click.stop="changeTask" v-if="!(phase.doPhase>phase.atPhase)">
-					<img :src="require('../../../../assets/icon/pblCourse/changeIcon.png')">
-					<span>更换任务</span>
-				</div>
-			</div>
-			<div class="w_nw_introduce">
-				<div v-html="htmlText(task.target)" style="font-weight: bold;"></div>
-				<div v-html="htmlText(task.detail)"></div>
-				<div v-html="htmlText(task.steps)"></div>
-				<div v-html="htmlText(task.tips)"></div>
-			</div>
-		</div>
-		<div class="w_doWork">
-			<div class="w_dw_header">
-				<div class="w_dw_h_title">
-					<img :src="require('../../../../assets/icon/pblCourse/doWorkIcon.png')">  
-					<span>通关挑战({{taskIndex+1}}/{{task.answerArray?task.answerArray.length:5}})</span>
-				</div>
-				<div class="w_dw_h_controls">
-					<span @click.stop="back()" :class="[taskIndex==0?'w_dw_h_c_disabled':'']">上一题</span>
-					<span @click.stop="down()" v-show="taskIndex!=4">下一题</span>
-					<span @click.stop="submitTask()" class="w_dw_h_c_submit" v-show="taskIndex==4">提交</span>
-				</div>
-			</div>
-			<div class="w_dw_work">
-					<span class="w_dw_w_title">{{ taskIndex+1 }}.{{ task.answerArray?task.answerArray[taskIndex].title:"" }}</span>
-					<div class="w_dw_w_radio">
-						<el-radio-group class="w_dw_w_r_group" v-model="task.answerArray[taskIndex].userAnswer" size="medium" @input="choiceAnswer">
-  					  <el-radio class="w_dw_w_r_g_item" v-for="(item,index) in task.answerArray?task.answerArray[taskIndex].option:[]" :key="index+''+taskIndex" size="medium " :label="index" @input="choiceAnswer">{{ item }}</el-radio>
-  					</el-radio-group>
-					</div>
-				</div>
-		</div>
-	</div>
+  <div class="work" ref="workRef" v-loading="loading">
+    <div class="w_nowWork">
+      <div class="w_nw_header">
+        <div class="w_nw_h_title">
+          <img
+            :src="require('../../../../assets/icon/pblCourse/taskIcon.png')"
+          />
+          <span>当前任务</span>
+        </div>
+        <div
+          class="w_nw_h_btn"
+          @click.stop="changeTask"
+          v-if="!(phase.doPhase > phase.atPhase)"
+        >
+          <img
+            :src="require('../../../../assets/icon/pblCourse/changeIcon.png')"
+          />
+          <span>更换任务</span>
+        </div>
+      </div>
+      <div class="w_nw_introduce">
+        <div v-html="htmlText(task.target)" style="font-weight: bold;"></div>
+        <div v-html="htmlText(task.detail)"></div>
+        <div v-html="htmlText(task.steps)"></div>
+        <div v-html="htmlText(task.tips)"></div>
+      </div>
+    </div>
+    <div class="w_doWork">
+      <div class="w_dw_header">
+        <div class="w_dw_h_title">
+          <img
+            :src="require('../../../../assets/icon/pblCourse/doWorkIcon.png')"
+          />
+          <span
+            >通关挑战({{ taskIndex + 1 }}/{{
+              task.answerArray ? task.answerArray.length : 5
+            }})</span
+          >
+        </div>
+        <div class="w_dw_h_controls">
+          <span
+            @click.stop="back()"
+            :class="[taskIndex == 0 ? 'w_dw_h_c_disabled' : '']"
+            >上一题</span
+          >
+          <span @click.stop="down()" v-show="taskIndex != 4">下一题</span>
+          <span
+            @click.stop="submitTask()"
+            class="w_dw_h_c_submit"
+            v-show="taskIndex == 4"
+            >提交</span
+          >
+        </div>
+      </div>
+      <div class="w_dw_work">
+        <span class="w_dw_w_title"
+          >{{ taskIndex + 1 }}.{{
+            task.answerArray ? task.answerArray[taskIndex].title : ""
+          }}</span
+        >
+        <div class="w_dw_w_radio">
+          <el-radio-group
+            class="w_dw_w_r_group"
+            v-model="task.answerArray[taskIndex].userAnswer"
+            size="medium"
+            @input="choiceAnswer"
+          >
+            <el-radio
+              class="w_dw_w_r_g_item"
+              v-for="(item, index) in task.answerArray
+                ? task.answerArray[taskIndex].option
+                : []"
+              :disabled="phase.doPhase > phase.atPhase"
+              :key="index + '' + taskIndex"
+              size="medium "
+              :label="index"
+              @input="choiceAnswer"
+              >{{ item }}</el-radio
+            >
+          </el-radio-group>
+        </div>
+      </div>
+    </div>
+    <div class="w_submitWork">
+      <div class="w_sw_header">
+        <div class="w_sw_h_title">
+          <img
+            :src="require('../../../../assets/icon/pblCourse/bookIcon.png')"
+          />
+          <span>提交作业</span>
+          <div class="w_sw_h_t_brief">
+            (支持txt、doc、xlsx、png、jpg、jpeg、wav格式的文件上传)
+          </div>
+        </div>
+        <div class="w_sw_h_controls">
+          <span @click="uploadFile">上传</span>
+          <span class="w_sw_h_t_submit" @click.stop="submitTask()">提交</span>
+        </div>
+      </div>
+      <div class="w_sw_fileBox" v-if="task.fileList.length > 0">
+        <div
+          :class="['w_sw_fb_item', index % 2 !== 0 ? 'w_sw_fb_item2' : '']"
+          v-for="(item, index) in task.fileList"
+          :key="index"
+        >
+          <div class="w_sw_fb_i_left" @click="previewFile(item)">
+            <img
+              :src="require('../../../../assets/icon/pblCourse/priFileImg.png')"
+            />
+            <span>{{ item.fileName }}</span>
+          </div>
+          <div class="w_sw_fb_i_right">
+            <el-tooltip
+              class="item"
+              effect="light"
+              content="删除"
+              placement="top"
+            >
+              <span
+                class="w_sw_fb_i_r_delete"
+                @click.stop="delFile(item, index)"
+              >
+                <img
+                  :src="require('../../../../assets/icon/pblCourse/del.png')"
+                />
+              </span>
+            </el-tooltip>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script>
-	import MarkdownIt from "markdown-it";
-	export default {
-		emits:['choiceAnswer','submitTask',"getTaskList"],
-		props:{
-			task:{
-				type:Object,
-				default:()=>{
-					return{
-						answerArray:[
-							{}
-						]
-					}
-				},
-				
-			},
-			phase:{
-				type:Object,
-				default:()=>{
-					return {
-						doPhase:0,
-						atPhase:0,
-					}
-				}
-			},
-
-		},
-		data(){
-			return{
-				taskIndex:0,
-				detail:"",
-				steps:"",
-				target:"",
-				tips:"",
-			}
-		},
-		computed:{
-			htmlText(){
-				return (mdText)=>{
-					const md = new MarkdownIt();
-					return md.render(mdText)
-				}
-			}
-		},
-		watch:{
-			task(){
-				this.taskIndex = 0;
-				this.$refs.workRef?this.$refs.workRef.scrollTop = 0:'';
-				// this.$refs.workRef.scrollTop = 0;
-			}
-		},
-		methods:{
-			changeTask(){
-				this.$emit("getTaskList",this.phase.atPhase)
-			},
-			back(){
-				if(this.taskIndex==0)return;
-				this.taskIndex-=1;
-			},
-			down(){
-				if(this.taskIndex>=(this.task?this.task.answerArray.length-1:5))return;
-				this.taskIndex+=1;
-			},
-			choiceAnswer(_index){
-				this.$emit("choiceAnswer",[this.taskIndex,_index])
-				this.$forceUpdate();
-			},
-			submitTask(){
-				if((this.phase.doPhase>this.phase.atPhase) || this.phase.doPhase>=5)return this.$message.error("该阶段已提交过了")
-				this.$emit("submitTask")
-			}
-		}
-	}
+import MarkdownIt from "markdown-it";
+import "@/common/aws-sdk-2.235.1.min.js";
+export default {
+  emits: [
+    "choiceAnswer",
+    "submitTask",
+    "getTaskList",
+    "deleteFile",
+    "addFile",
+    "lookFile"
+  ],
+  props: {
+    task: {
+      type: Object,
+      default: () => {
+        return {
+          answerArray: [{}]
+        };
+      }
+    },
+    phase: {
+      type: Object,
+      default: () => {
+        return {
+          doPhase: 0,
+          atPhase: 0
+        };
+      }
+    }
+  },
+  data() {
+    return {
+      taskIndex: 0,
+      detail: "",
+      steps: "",
+      target: "",
+      tips: "",
+      loading: false
+    };
+  },
+  computed: {
+    htmlText() {
+      return mdText => {
+        const md = new MarkdownIt();
+        return md.render(mdText);
+      };
+    }
+  },
+  watch: {
+    task() {
+      this.taskIndex = 0;
+      this.$refs.workRef ? (this.$refs.workRef.scrollTop = 0) : "";
+      // this.$refs.workRef.scrollTop = 0;
+    }
+  },
+  methods: {
+    changeTask() {
+      this.$emit("getTaskList", this.phase.atPhase);
+    },
+    back() {
+      if (this.taskIndex == 0) return;
+      this.taskIndex -= 1;
+    },
+    down() {
+      if (this.taskIndex >= (this.task ? this.task.answerArray.length - 1 : 5))
+        return;
+      this.taskIndex += 1;
+    },
+    choiceAnswer(_index) {
+      this.$emit("choiceAnswer", [this.taskIndex, _index]);
+      this.$forceUpdate();
+    },
+    submitTask() {
+      //   console.log(this.phase.doPhase, this.phase.atPhase);
+      if (this.phase.doPhase == 5) {
+        return this.$message("所有阶段已经完成");
+      }
+      if (this.phase.doPhase > this.phase.atPhase || this.phase.doPhase >= 5)
+        return this.$message.error("该阶段已提交过了");
+      this.$emit("submitTask");
+    },
+    submitTask2() {
+      return console.log("第二个提交");
+    },
+    uploadFile() {
+      let input = document.createElement("input");
+      input.type = "file";
+      input.accept = "*";
+      input.click();
+      input.onchange = () => {
+        this.uploadFileLoading = true;
+        let file = input.files[0];
+        // if(!/\.(wav|txt|pdf|xlsx|doc|docx)$/i.test(file.name)){
+        // 	this.uploadFileLoading = false;
+        // 	return this.$message.info("请上传.wav,.txt,.pdf,.xlsx,.doc,.docx格式的文件")
+        // }
+        var credentials = {
+          accessKeyId: "AKIATLPEDU37QV5CHLMH",
+          secretAccessKey: "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"
+        }; //秘钥形式的登录上传
+        window.AWS.config.update(credentials);
+        window.AWS.config.region = "cn-northwest-1"; //设置区域
+
+        var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } }); //选择桶
+        var _this = this;
+
+        if (file) {
+          this.loading = true;
+          var params = {
+            Key:
+              file.name.split(".")[0] +
+              new Date().getTime() +
+              "." +
+              file.name.split(".")[file.name.split(".").length - 1],
+            ContentType: file.type,
+            Body: file,
+            "Access-Control-Allow-Credentials": "*",
+            ACL: "public-read"
+          }; //key可以设置为桶的相抵路径,Body为文件, ACL最好要设置
+          var options = {
+            partSize: 2048 * 1024 * 1024,
+            queueSize: 2,
+            leavePartsOnError: true
+          };
+          bucket
+            .upload(params, options)
+            .on("httpUploadProgress", function(evt) {
+              //这里可以写进度条
+              // console.log("Uploaded : " + parseInt((evt.loaded * 80) / evt.total) + '%');
+            })
+            .send(function(err, data) {
+              if (err) {
+                _this.$message.error("上传失败");
+                _this.loading = false;
+              } else {
+                _this.loading = false;
+                _this.$emit("addFile", {
+                  fileName: data.key,
+                  url: data.Location
+                });
+                // _this.fileList.push({
+                // 	fileName:data.key,
+                // 	url:data.Location,
+                // })
+                console.log(data);
+              }
+            });
+        }
+      };
+    },
+    delFile(_item, _index) {
+      this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      })
+        .then(() => {
+          this.$emit("deleteFile", _index);
+          // this.fileList.splice(_index,1);
+        })
+        .catch(_ => {
+          console.log("取消删除");
+        });
+    },
+    previewFile(_item) {
+      console.log(_item);
+      if (/\.(jpeg|jpg|png|img)$/i.test(_item.url)) {
+        this.$hevueImgPreview(_item.url);
+      } else {
+        this.$emit("lookFile", _item.url);
+      }
+      // this.$message.info(`预览文件:${_item.filename}`)
+    }
+  }
+};
 </script>
 
 <style scoped>
-.work{
-	width: 100%;
-	max-height: 100%;
-	overflow: auto;
-	box-sizing: border-box;
-	padding: 25px;
-	/* background-color: aqua; */
+.work {
+  width: 100%;
+  height: auto;
+  box-sizing: border-box;
+  /* padding: 25px; */
+  /* background-color: aqua; */
 }
 
-.w_nowWork{
-	width: 100%;
-	height: auto;
-	margin-bottom: 20px;
+.w_nowWork {
+  width: 100%;
+  height: auto;
+  margin-bottom: 20px;
+  background-color: #f3f7fd;
+  box-sizing: border-box;
+  padding: 20px;
+  border-radius: 8px;
 }
 
-.w_nw_header{
-	width: 100%;
-	display: flex;
-	justify-content: space-between;
-	height: 35px;
-	margin-bottom: 20px;
+.w_nw_header {
+  width: 100%;
+  display: flex;
+  justify-content: space-between;
+  height: 35px;
+  margin-bottom: 20px;
 }
 
-.w_nw_h_title{
-	display: flex;
-	align-items: center;
+.w_nw_h_title {
+  display: flex;
+  align-items: center;
 }
 
-.w_nw_h_title>img{
-	width: 50px;
-	height: 50px;
-	margin-right: 10px;
+.w_nw_h_title > img {
+  width: 50px;
+  height: 50px;
+  margin-right: 10px;
 }
 
-.w_nw_h_title>span{
-	font-size: 24px;
-	font-weight: bold;
-	background: linear-gradient(to right, #3673E8, #AD88FD);
-	-webkit-background-clip: text;
-	color: transparent;
+.w_nw_h_title > span {
+  font-size: 24px;
+  font-weight: bold;
+  background: linear-gradient(to right, #3673e8, #ad88fd);
+  -webkit-background-clip: text;
+  color: transparent;
 }
 
-.w_nw_h_btn{
-	width: auto;
-	height: 100%;
-	border-radius: 100px;
-	box-sizing: border-box;
-	border: solid 1px #AD88FD;
-	background-color: white;
-	display: flex;
-	justify-content: center;
-	align-items: center;
-	padding: 0px 20px 0 10px;
-	cursor: pointer;
-	transition: .3s;
+.w_nw_h_btn {
+  width: auto;
+  height: 100%;
+  border-radius: 100px;
+  box-sizing: border-box;
+  border: solid 1px #ad88fd;
+  background-color: white;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  padding: 0px 20px 0 10px;
+  cursor: pointer;
+  transition: 0.3s;
 }
 
-.w_nw_h_btn:hover{
-	background-color: rgb(248, 246, 246);
+.w_nw_h_btn:hover {
+  background-color: rgb(248, 246, 246);
 }
 
-.w_nw_h_btn>img{
-	width: 20px;
-	height: 20px;
-	margin-right: 10px;
+.w_nw_h_btn > img {
+  width: 20px;
+  height: 20px;
+  margin-right: 10px;
 }
 
-.w_nw_h_btn>span{
-	font-size: 16px;
+.w_nw_h_btn > span {
+  font-size: 16px;
 }
 
-.w_nw_introduce>div{
-	margin: 10px 0px;
+.w_nw_introduce > div {
+  margin: 20px 0px;
 }
 
-.w_nw_introduce >>> ol{
-	margin-left: 25px;
+.w_nw_introduce >>> ol {
+  margin-left: 25px;
 }
 
 .w_nw_introduce >>> ul {
-	margin-left: 25px;
+  margin-left: 25px;
 }
 
-.w_nw_introduce >>> h2{
-	margin-top: 10px;
+.w_nw_introduce >>> h2 {
+  margin-top: 10px;
 }
-.w_nw_introduce >>> h3{
-	margin-top: 10px;
+.w_nw_introduce >>> h3 {
+  margin-top: 10px;
 }
-.w_nw_introduce >>> h4{
-	margin-top: 10px;
+.w_nw_introduce >>> h4 {
+  margin-top: 10px;
 }
-.w_nw_introduce >>> h5{
-	margin-top: 10px;
+.w_nw_introduce >>> h5 {
+  margin-top: 10px;
 }
-.w_nw_introduce >>> h6{
-	margin-top: 10px;
+.w_nw_introduce >>> h6 {
+  margin-top: 10px;
 }
 
+.w_doWork {
+  width: 100%;
+  height: auto;
+  box-sizing: border-box;
+  padding: 20px;
+  background-color: #f3f7fd;
+  margin-bottom: 20px;
+  border-radius: 8px;
+}
+
+.w_dw_header {
+  width: 100%;
+  display: flex;
+  justify-content: space-between;
+  height: 35px;
+  margin-bottom: 20px;
+}
+
+.w_dw_h_title {
+  display: flex;
+  align-items: center;
+}
 
+.w_dw_h_title > img {
+  width: 50px;
+  height: 50px;
+  margin-right: 10px;
+}
 
-.w_doWork{
-	width: 100%;
-	height: auto;
+.w_dw_h_title > span {
+  font-size: 24px;
+  font-weight: bold;
+  background: linear-gradient(to right, #3673e8, #ad88fd);
+  -webkit-background-clip: text;
+  color: transparent;
 }
 
-.w_dw_header{
-	width: 100%;
-	display: flex;
-	justify-content: space-between;
-	height: 35px;
-	margin-bottom: 20px;
+.w_dw_h_controls {
+  display: flex;
+  align-items: center;
 }
 
-.w_dw_h_title{
-	display: flex;
-	align-items: center;
+.w_dw_h_c_disabled {
+  opacity: 0.5;
+  cursor: not-allowed !important;
 }
 
-.w_dw_h_title>img{
-	width: 50px;
-	height: 50px;
-	margin-right: 10px;
+.w_dw_h_c_submit {
+  background: linear-gradient(to right, #6082e5, #a293f3);
+  color: white;
+  padding: 0 23px !important;
+  /* 不可选中 */
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
 }
 
-.w_dw_h_title>span{
-	font-size: 24px;
-	font-weight: bold;
-	background: linear-gradient(to right, #3673E8, #AD88FD);
-	-webkit-background-clip: text;
-	color: transparent;
+.w_dw_h_controls > span {
+  font-size: 16px;
+  margin-left: 20px;
+  cursor: pointer;
+  transition: 0.3s;
+  box-sizing: border-box;
+  padding: 0 15px;
+  background-color: white;
+  height: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  border-radius: 100px;
+  border: solid 1px #ad88fd;
+  /* 不可选中 */
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
 }
 
-.w_dw_h_controls{
-	display: flex;
-	align-items: center;
+.w_dw_h_controls > span:hover {
+  background-color: rgb(248, 246, 246);
 }
 
-.w_dw_h_c_disabled{
-	opacity: .5;
-	cursor: not-allowed !important;
+.w_dw_work {
+  width: 100%;
+  height: auto;
 }
 
-.w_dw_h_c_submit{
-	background:linear-gradient(to right,#6082E5,#A293F3);
-	color: white;
-	padding: 0 23px !important;
-	/* 不可选中 */
-	-webkit-user-select: none;
-	-moz-user-select: none;
-	-ms-user-select: none;
-	user-select: none;
+.w_dw_w_title {
+  font-size: 20px;
+  font-weight: bold;
 }
 
+.w_dw_w_radio {
+  margin-top: 10px;
+}
 
-.w_dw_h_controls>span{
-	font-size: 16px;
-	margin-left: 20px;
-	cursor: pointer;
-	transition: .3s;
-	box-sizing: border-box;
-	padding: 0 15px;
-	background-color: white;
-	height: 100%;
-	display: flex;
-	justify-content: center;
-	align-items: center;
-	border-radius: 100px;
-	border: solid 1px #AD88FD;
-	/* 不可选中 */
-	-webkit-user-select: none;
-	-moz-user-select: none;
-	-ms-user-select: none;
-	user-select: none;
+.w_dw_w_r_group {
+  display: flex;
+  flex-direction: column;
+  margin-top: 10px;
 }
 
-.w_dw_h_controls>span:hover{
-	background-color: rgb(248, 246, 246);
+.w_dw_w_r_g_item {
+  margin-top: 15px;
 }
 
-.w_dw_work{
-	width: 100%;
-	height: auto;
+.w_dw_w_r_g_item >>> .el-radio__label {
+  font-size: 16px;
+}
+
+.w_dw_w_r_g_item >>> .el-radio__inner {
+  width: 20px;
+  height: 20px;
+  margin-right: 5px;
+}
 
+.w_submitWork {
+  width: 100%;
+  height: auto;
+  background-color: #f3f7fd;
+  margin-bottom: 20px;
+  box-sizing: border-box;
+  padding: 20px;
+  border-radius: 8px;
 }
 
-.w_dw_w_title{
-	font-size: 24px;
-	font-weight: bold;
+.w_sw_header {
+  width: 100%;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 35px;
+}
+
+.w_sw_h_title {
+  display: flex;
+  align-items: center;
+}
+
+.w_sw_h_title > img {
+  width: 50px;
+  height: 50px;
+  margin-right: 10px;
+}
+
+.w_sw_h_title > span {
+  font-size: 24px;
+  font-weight: bold;
+  flex-shrink: 0;
+  background: linear-gradient(to right, #3673e8, #ad88fd);
+  -webkit-background-clip: text;
+  color: transparent;
+}
+
+.w_sw_h_t_brief {
+  font-size: 20px !important;
+  color: #00000066 !important;
+  font-weight: 400 !important;
+  margin-left: 20px;
+}
+
+.w_sw_h_controls {
+  display: flex;
+  align-items: center;
+}
+
+.w_sw_h_controls > span {
+  font-size: 16px;
+  margin-left: 20px;
+  flex-shrink: 0;
+  cursor: pointer;
+  transition: 0.3s;
+  box-sizing: border-box;
+  /* padding: 0 15px; */
+  padding: 0 23px;
+  background-color: white;
+  height: 35px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  border-radius: 100px;
+  border: solid 1px #ad88fd;
+  /* 不可选中 */
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+
+.w_sw_h_controls > span:hover {
+  background-color: rgb(248, 246, 246);
+}
+
+.w_sw_h_t_submit {
+  background: linear-gradient(to right, #6082e5, #a293f3);
+  color: white;
+}
+
+.w_sw_fileBox {
+  width: 100%;
+  height: auto;
+  margin-top: 20px;
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.w_sw_fb_item {
+  width: 49.5%;
+  height: 45px;
+  margin-bottom: 10px;
+  margin-right: 1%;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  box-sizing: border-box;
+  padding: 0 10px;
+  background-color: #ffffff;
+  border: solid 1px #e7e7e7;
+  border-radius: 4px;
+  position: relative;
+}
+
+.w_sw_fb_item:hover {
+  border: solid 1px #3681fc;
+}
+
+.w_sw_fb_item2 {
+  margin-right: 0 !important;
+}
+
+.w_sw_fb_i_left {
+  width: calc(100% - 80px);
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  position: relative;
+}
+
+.w_sw_fb_i_left > span {
+  /* 字体溢出隐藏 */
+  width: 80%;
+  display: block;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
 }
 
-.w_dw_w_radio{
-	margin-top: 10px;
+.w_sw_fb_i_left > img {
+  width: 15px;
+  height: 15px;
+  margin-right: 10px;
 }
 
-.w_dw_w_r_group{
-	display: flex;
-	flex-direction: column;
-	margin-top: 10px;
+.w_sw_fb_i_right {
+  width: 80px;
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  height: auto;
 }
 
-.w_dw_w_r_g_item{
-	margin-top: 15px;
+.w_sw_fb_item:hover .w_sw_fb_i_r_delete {
+  display: flex;
 }
 
-.w_dw_w_r_g_item>>>.el-radio__label{
-	font-size: 22px;
+.w_sw_fb_i_right > span {
+  width: 30px;
+  height: 30px;
+  background-color: #f3f7fd;
+  display: none;
+  border-radius: 4px;
+  justify-content: center;
+  align-items: center;
+  cursor: pointer;
 }
 
-.w_dw_w_r_g_item>>>.el-radio__inner{
-	width: 20px;
-	height: 20px;
-	margin-right: 5px;
+.w_sw_fb_i_right > span > img {
+  width: 25px;
+  height: 25px;
 }
-</style>
+</style>

+ 674 - 0
src/components/pages/pblCourse/guide.vue

@@ -0,0 +1,674 @@
+<template>
+  <div class="guide">
+    <div style="padding-top: 60px;" v-if="show == 0">
+      <div class="guideIndex">
+        <img
+          style="width: 200px;height: 200px;"
+          src="../../../assets/icon/pblCourse/helloworldQs.gif"
+          alt=""
+        />
+        <div class="guideIndexCon">
+          Hi~ 同学!😆 <br />
+          我是什么都知道的小可老师!😎 <br />
+          接下来,我会陪你一起学习这节课程!🧐 <br />
+          你,准备好了吗?😝
+        </div>
+        <div class="guideBtn" @click="dialogVisible = true">
+          <img
+            style="cursor: pointer"
+            src="../../../assets/icon/pblCourse/guidebtn.png"
+            alt=""
+          />
+        </div>
+      </div>
+
+      <div class="guideList">
+        <div class="guideListTop">
+          <div style="display: flex; align-items: center">
+            <img
+              style="margin-right: 10px"
+              src="../../../assets/icon/pblCourse/cardimg.png"
+              alt=""
+            />
+            <div class="guideListTopL">项目列表</div>
+          </div>
+          <div class="guideListTopR">
+            <div
+              style="display: flex; align-items: center; cursor: pointer"
+              @click="cutMoreProject"
+            >
+              <div class="guideListTopL">查看全部</div>
+              <img
+                style="margin-right: 10px"
+                src="../../../assets/icon/pblCourse/chevronRight.png"
+                alt=""
+              />
+            </div>
+          </div>
+        </div>
+
+        <div class="guideListListCon">
+          <div class="guideListLeft">
+            <img
+              v-if="Homepage == 1"
+              @click="Pre"
+              src="../../../assets/icon/pblCourse/FrameLeft.png"
+              alt=""
+            />
+            <img
+              v-else
+              @click="Pre"
+              style="transform: rotate(180deg);"
+              src="../../../assets/icon/pblCourse/FrameRig.png"
+              alt=""
+            />
+          </div>
+          <div class="guideListRig">
+            <img
+              @click="Nxt"
+              v-if="nowNxt"
+              src="../../../assets/icon/pblCourse/FrameRig.png"
+              alt=""
+            />
+            <img
+              v-else
+              @click="Nxt"
+              style="transform: rotate(180deg);"
+              src="../../../assets/icon/pblCourse/FrameLeft.png"
+              alt=""
+            />
+          </div>
+          <div
+            v-for="(i, index) in homeProList"
+            :key="i.courseId"
+            class="guideListListConCard"
+            @click="gotoProDetail(i.courseId)"
+          >
+            <img
+              height="102px"
+              src="../../../assets/icon/pblCourse/guidebook.png"
+              alt=""
+            />
+            <div class="CardCon">
+              <div class="conTit">{{ i.title }}</div>
+              <div class="conTxt">
+                <div style="margin-right: 5px;">{{ i.time }}</div>
+                <div style="flex: 1;">
+                  <bars :doIndex="i.doIndex" :key="i.doIndex.toString()"></bars>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div v-if="show == 1">
+      <div class="moreProTop">
+        <div class="moreProSelect">
+          <el-select v-model="CheckboxCon" placeholder="请选择">
+            <el-option label="全部项目" :value="1"> </el-option>
+            <el-option
+              v-for="item in options"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+          <el-input
+            v-model="selectInp"
+            suffix-icon="el-icon-search"
+            placeholder="搜索"
+          >
+          </el-input>
+          <div class="ResetBtn" @click="ResetSelect">重置</div>
+        </div>
+        <div class="addPro" @click="dialogVisible = true">
+          <img
+            style="margin-right: 5px"
+            src="../../../assets/icon/pblCourse/addPro.png"
+            alt=""
+          />
+          <span>新建项目</span>
+        </div>
+      </div>
+      <div class="moreProCon">
+        <div class="guideListListConCard moreProConIndCss">
+          <img
+            style="margin-bottom: 10px"
+            src="../../../assets/icon/pblCourse/addTitImg.png"
+            alt=""
+          />
+          <div class="addPro" @click="dialogVisible = true">
+            <img
+              style="margin-right: 5px"
+              src="../../../assets/icon/pblCourse/addPro.png"
+              alt=""
+            />
+            <span>新建项目</span>
+          </div>
+        </div>
+        <div
+          v-for="(i, index) in ProList"
+          :key="i.courseId"
+          class="guideListListConCard"
+          @click="gotoProDetail(i.courseId)"
+        >
+          <img
+            height="102px"
+            src="../../../assets/icon/pblCourse/guidebook.png"
+            alt=""
+          />
+          <div class="CardCon">
+            <div class="conTit">{{ i.title }}</div>
+            <div class="conTxt">
+              <div style="margin-right: 5px;">{{ i.time }}</div>
+              <div style="flex: 1;">
+                <bars :doIndex="i.doIndex" :key="i.doIndex.toString()"></bars>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div style="min-width: 928px;max-width: 1100px;margin: 15px auto;">
+        <el-pagination
+          background
+          layout="prev, pager, next"
+          :page-size="14"
+          @current-change="handleCurrentChange"
+          :total="total"
+        >
+        </el-pagination>
+      </div>
+    </div>
+    <el-dialog :visible.sync="dialogVisible" width="414px">
+      <img src="../../../assets/icon/pblCourse/huishou.png" alt="" />
+      <div class="digTit">选题设置</div>
+
+      <div class="digInp">
+        <div style="text-wrap: nowrap;">项目标题:</div>
+        <el-input v-model.trim="proTit" placeholder="请输入标题"></el-input>
+      </div>
+      <div class="digInp">
+        <div style="text-wrap: nowrap;">项目选题:</div>
+        <el-input v-model.trim="proType" placeholder="请输入选题"></el-input>
+      </div>
+      <div class="digBtn" @click="addProject">确认</div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import bars from "./component/bars";
+export default {
+  components: {
+    bars
+  },
+  data() {
+    return {
+      show: 0, //主页0与更多详情页1
+      page: 1, //全部页面数据页数
+      Homepage: 1, //主页数据页数
+      homeTotal: 0,
+      CheckboxCon: 1, //下拉框数据
+      dialogVisible: false, //添加课程弹窗
+      proType: "", //项目选题
+      proTit: "", //项目标题
+      selectInp: "",
+      userid: this.$route.query.userid,
+      org: this.$route.query.org,
+      oid: this.$route.query.oid,
+      int: 14,
+      total: 0,
+      input: "",
+      ProList: [],
+      homeProList: [],
+      options: []
+    };
+  },
+  watch: {
+    selectInp(newVal, oldVal) {
+      this.getData();
+    },
+    CheckboxCon(newVal, oldVal) {
+      this.getData();
+    }
+  },
+  computed: {
+    nowNxt: function() {
+      return this.homeTotal - this.Homepage * 5 > 0;
+    }
+  },
+  mounted() {
+    // console.log("state", this.$store);
+    this.getHomeData();
+  },
+  methods: {
+    // 去答题页面
+    gotoProDetail(courseId) {
+      this.$router.push(
+        "/pblCourse?cid=" +
+          courseId +
+          "&userid=" +
+          this.userid +
+          "&oid=" +
+          this.oid +
+          "&org=" +
+          this.org
+      );
+    },
+    // 重置搜索
+    ResetSelect() {
+      this.CheckboxCon = 1;
+      this.selectInp = "";
+      this.getData();
+    },
+    //删除项目
+    delPro(val) {
+      let params = [
+        {
+          cid: val
+        }
+      ];
+      this.ajax
+        .post(this.$store.state.api + "deletePblStudent", params)
+        .then(res => {
+          console.log(res);
+          this.$message({
+            type: "success",
+            message: "删除成功"
+          });
+          if (this.show == 0) {
+            this.getHomeData();
+          } else {
+            this.getData();
+          }
+        });
+    },
+    addProject() {
+      if (this.proTit == "") {
+        this.$message({
+          type: "error",
+          message: "请输入项目标题"
+        });
+        return;
+      }
+      if (this.proType == "") {
+        this.$message({
+          type: "error",
+          message: "请输入项目选题"
+        });
+        return;
+      }
+      let params = [
+        {
+          uid: this.$route.query.userid,
+          t: this.proTit,
+          n: this.proType
+        }
+      ];
+      console.log(params);
+      this.ajax
+        .post(this.$store.state.api + "addPblStudent", params)
+        .then(res => {
+          console.log(res);
+          this.dialogVisible = false;
+          this.$message({
+            type: "success",
+            message: "创建成功"
+          });
+          this.proTit = "";
+          this.proType = "";
+          if (this.show == 0) {
+            this.getHomeData();
+          } else {
+            this.getData();
+          }
+          // this.isLoading = false;
+        })
+        .catch(err => {
+          // this.isLoading = false;
+          console.error(err);
+        });
+    },
+    Pre() {
+      if (this.Homepage == 1) {
+        this.$message("已经是第一页了");
+      } else {
+        this.Homepage -= 1;
+        this.getHomeData();
+      }
+    },
+    Nxt() {
+      console.log(this.homeTotal - this.Homepage * 5);
+
+      if (this.homeTotal - this.Homepage * 5 > 0) {
+        this.Homepage += 1;
+        this.getHomeData();
+      } else {
+        this.$message("已经是最后一页了");
+      }
+    },
+    getHomeData() {
+      let params = {
+        uid: this.userid,
+        org: this.org,
+        oid: this.oid,
+        type: 1,
+        n: "",
+        page: this.Homepage,
+        int: 5
+      };
+      // console.log(params);
+      this.ajax
+        .get(this.$store.state.api + "selectPblStudent", params)
+        .then(res => {
+          console.log(res);
+          // this.isLoading = false;
+          let data = res.data[0];
+          this.homeProList = data;
+          this.homeTotal = data.length > 0 ? data[0].num : 0;
+        })
+        .catch(err => {
+          // this.isLoading = false;
+          console.error(err);
+        });
+    },
+    getData() {
+      let params = {
+        uid: this.userid,
+        org: this.org,
+        oid: this.oid,
+        type: this.CheckboxCon,
+        n: this.selectInp,
+        page: this.page,
+        int: this.int
+      };
+      // console.log(params);
+      this.ajax
+        .get(this.$store.state.api + "selectPblStudent", params)
+        .then(res => {
+          console.log(res);
+          // this.isLoading = false;
+          let data = res.data[0];
+          this.ProList = data;
+
+          // console.log("this.tableData", this.tableData);
+          this.total = data.length > 0 ? data[0].num : 0;
+          // console.log(" 获取筛选数据", res.data[0]);
+        })
+        .catch(err => {
+          // this.isLoading = false;
+          console.error(err);
+        });
+    },
+    handleCurrentChange(val) {
+      console.log(`当前页: ${val}`);
+      this.page = val;
+    },
+    cutMoreProject() {
+      this.show = 1;
+      this.getData();
+    }
+  }
+};
+</script>
+
+<style scoped>
+.digTit {
+  font-family: PingFang SC;
+  font-size: 20px;
+  font-weight: 600;
+  line-height: 28px;
+  text-align: center;
+  color: rgba(0, 0, 0, 0.9);
+  margin: 10px 0;
+}
+.digInp {
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
+  margin-bottom: 10px;
+  font-size: 16px;
+}
+.digInp >>> .el-select {
+  width: 206px !important;
+}
+.digBtn {
+  width: 128px;
+  height: 40px;
+  margin-top: 20px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  cursor: pointer;
+  border-radius: 30px;
+  color: rgba(255, 255, 255, 0.9);
+  background: linear-gradient(90deg, #3673e8 0%, #ad88fd 100%);
+}
+.moreProConIndCss {
+  background: linear-gradient(180deg, #fafcff 0%, #e7eefe 100%);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+}
+.moreProCon {
+  min-width: 928px;
+  max-width: 1100px;
+  margin: auto;
+  min-height: 660px;
+  max-height: 670px;
+  overflow: auto;
+  margin-top: 30px;
+}
+.moreProCon > .guideListListConCard {
+  margin-right: calc((100% - 880px) / 4) !important;
+  margin-bottom: calc((100% - 880px) / 5) !important;
+  float: left;
+}
+.moreProCon :nth-child(5n) {
+  margin-right: 0 !important;
+  float: right;
+}
+.moreProTop {
+  padding-top: 60px;
+  min-width: 928px;
+  max-width: 1100px;
+  margin: auto;
+  display: flex;
+  justify-content: space-between;
+}
+.moreProSelect {
+  display: flex;
+  width: 560px;
+  justify-content: space-between;
+  align-items: center;
+}
+.moreProSelect >>> .el-input__inner {
+  width: 220px;
+  background: none !important;
+  border: 1px #fff solid;
+}
+.moreProSelect >>> .el-input {
+  width: 220px;
+}
+.ResetBtn {
+  width: 80px;
+  height: 100%;
+  border-radius: 30px;
+  display: flex;
+  font-size: 16px;
+  color: rgba(54, 115, 232, 1);
+  border: 1px solid rgba(255, 255, 255, 0.9);
+  justify-content: center;
+  align-items: center;
+  cursor: pointer;
+}
+.addPro {
+  width: 112px;
+  height: 32px;
+  border-radius: 30px;
+  background: linear-gradient(90deg, #3673e8 0%, #ad88fd 100%);
+  color: rgba(255, 255, 255, 0.9);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  font-size: 14px;
+  cursor: pointer;
+}
+.guide {
+  width: 100%;
+  min-height: 100%;
+  box-sizing: border-box;
+  overflow: auto;
+  overflow-y: hidden;
+  background-image: radial-gradient(#c6d6ff, #d0d1fe, #f3f7ff);
+}
+.guide >>> .el-dialog {
+  border-radius: 10px;
+}
+.guide >>> .el-dialog__body {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+.guideIndex {
+  margin: auto;
+  width: 480px;
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+}
+.guideIndex > img {
+  transform: translate(0, 50px);
+  z-index: 0;
+}
+.guideIndex > .guideIndexCon {
+  background: rgba(255, 255, 255, 1);
+  border: 2px solid rgba(0, 42, 42, 1);
+  border-radius: 16px;
+  box-sizing: border-box;
+  padding: 15px;
+  z-index: 2;
+  margin-bottom: 30px;
+  width: 100%;
+  font-size: 18px;
+  font-family: PingFang SC;
+  font-weight: 400;
+  color: #3773e8;
+  line-height: 28px;
+  text-align: left;
+}
+.guideIndex > .guideBtn {
+  width: 248px;
+  height: 56px;
+  border-radius: 25px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: rgba(99, 62, 18, 1);
+  background-color: #f1cc63;
+  font-family: PingFang SC;
+  font-size: 20px;
+  font-weight: 400;
+  line-height: 28px;
+  text-align: center;
+}
+.guideList {
+  width: 928px;
+  height: 216px;
+  margin: auto;
+  margin-top: 80px;
+}
+.guideList > .guideListTop {
+  width: 100%;
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 20px;
+  align-items: center;
+}
+.guideListTop > .guideListTopL {
+  font-family: PingFang SC;
+  font-size: 16px;
+  font-weight: 400;
+  line-height: 24px;
+  text-align: left;
+  color: rgba(67, 78, 105, 1);
+}
+.guideListTop > .guideListTopR {
+  font-family: PingFang SC;
+  font-size: 14px;
+  font-weight: 400;
+  line-height: 24px;
+  text-align: left;
+  color: rgba(54, 129, 252, 1);
+}
+.guideList > .guideListListCon {
+  width: 100%;
+  position: relative;
+  display: flex;
+  min-height: 176px;
+  /* justify-content: space-between; */
+}
+.guideListListCon > .guideListListConCard {
+  margin-right: calc((100% - 880px) / 4) !important;
+}
+.guideListListCon :nth-child(5n + 2) {
+  margin-right: 0 !important;
+}
+.guideListLeft {
+  position: absolute;
+  left: -80px;
+  top: 50%;
+  transform: translate(0, -50%);
+}
+.guideListLeft > img {
+  cursor: pointer;
+}
+.guideListRig {
+  position: absolute;
+  right: -80px;
+  top: 50%;
+  transform: translate(0, -50%);
+}
+.guideListRig > img {
+  cursor: pointer;
+}
+.guideListListConCard {
+  background-color: #fff;
+  width: 176px;
+  height: 176px;
+  border-radius: 12px;
+  overflow: hidden;
+  cursor: pointer;
+}
+.guideListListConCard > .CardCon {
+  box-sizing: border-box;
+  padding: 10px;
+}
+.CardCon > .conTit {
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  font-family: PingFang SC;
+  font-size: 16px;
+  font-weight: 600;
+  line-height: 24px;
+  color: rgba(0, 0, 0, 1);
+}
+.CardCon > .conTxt {
+  font-size: 12px;
+  font-family: PingFang SC;
+  font-size: 14px;
+  font-weight: 400;
+  line-height: 22px;
+  text-align: left;
+  color: rgba(0, 0, 0, 0.4);
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+</style>

+ 359 - 167
src/components/pages/pblCourse/index.vue

@@ -1,54 +1,151 @@
 <template>
-	<div class="pblCourse" v-loading="loading">
-		<div class="pc_left">
-			<div class="pc_l_top">
-				<procedureArea :phase="phase" />
-			</div>
-			<div class="pc_l_bottom">
-				<doWorkArea :phase="phase" @changePhase="changePhase" @choiceAnswer="choiceAnswer" @submitTask="submitTask" :task="taskList[phase.atPhase]" @getTaskList="getTaskList"/>
-			</div>
-		</div>
-		<div class="pc_right">
-			<chatArea />
-		</div>
-		<selectTopicDialog ref="selectTopicDialogRef" @success="selectTopicSuccess"/>
-	</div>
+  <div class="pblCourse" v-loading="loading">
+    <div class="pc_left">
+      <div class="pc_l_top">
+        <procedureArea :phase="phase" />
+      </div>
+      <div class="pc_l_bottom">
+        <doWorkArea
+          :phase="phase"
+          @changePhase="changePhase"
+          @choiceAnswer="choiceAnswer"
+          @submitTask="submitTask"
+          :task="taskList[phase.atPhase]"
+          @getTaskList="getTaskList"
+          @lookFile="lookFile"
+          @addFile="addFile"
+          @deleteFile="deleteFile"
+        />
+      </div>
+    </div>
+    <div class="pc_right">
+      <chatArea />
+    </div>
+    <selectTopicDialog
+      ref="selectTopicDialogRef"
+      @success="selectTopicSuccess"
+    />
+    <div class="BackBtn" @click="backPage">返回</div>
+    <el-dialog
+      title="查看"
+      :visible.sync="priDiaVisible"
+      :before-close="handleClose"
+    >
+      <iframe
+        ref="viframe"
+        v-if="/\.(xlsx|doc|docx)$/i.test(priFile)"
+        style="width: 100%; height: 100%; border: none"
+        :src="`https://view.officeapps.live.com/op/view.aspx?src=${priFile}`"
+      ></iframe>
+      <vpdf
+        style="width: 100%; height: 100%; border: none"
+        :pdfUrl="priFile"
+        v-if="/\.(pdf)$/i.test(priFile)"
+      />
+      <img
+        v-if="/\.(jpeg|jpg|png|img)$/i.test(priFile)"
+        :src="priFile"
+        @click="previewImg(priFile)"
+        style="max-width: 100%;max-height: 100%;"
+        alt=""
+      />
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="priDiaVisible = false">关闭</el-button>
+      </span>
+    </el-dialog>
+  </div>
 </template>
 
 <script>
-import chatArea from './component/chatArea'
-import doWorkArea from './component/doWorkArea'
-import procedureArea from './component/procedureArea'
+import chatArea from "./component/chatArea";
+import doWorkArea from "./component/doWorkArea";
+import procedureArea from "./component/procedureArea";
 import { v4 as uuidv4 } from "uuid";
-import selectTopicDialog from './component/selectTopicDialog'
+import vpdf from "./component/vpdf";
+
+import selectTopicDialog from "./component/selectTopicDialog";
 export default {
-	components: {
-		chatArea,
-		doWorkArea,
-		procedureArea,
-		selectTopicDialog,
-	},
-	data() {
-		return {
-			loading: false,
-			phase:{
-				doPhase:0,
-				atPhase:0,
-			},
-			selectTopic:"",
-			taskList:[]
-		};
-	},
-	methods: {
-		changePhase(type,newValue){
-			this.phase[type] = newValue;
-		},
-		getTaskList(phase = 0){
-			return new Promise((resolve,reject)=>{
-				if(this.loading)return this.$message.info("请稍等")
-			this.loading = true;
-		const _uuid = uuidv4()
-		const _msg = `
+  components: {
+    chatArea,
+    doWorkArea,
+    procedureArea,
+    selectTopicDialog,
+    vpdf
+  },
+  data() {
+    return {
+      loading: false,
+      phase: {
+        doPhase: 0,
+        atPhase: 0
+      },
+      showIndexPage: 0,
+      Completion: 0,
+      cid: this.$route.query.cid,
+      userid: this.$route.query.userid,
+      org: this.$route.query.org,
+      oid: this.$route.query.oid,
+      selectTopic: "",
+      taskList: [],
+      priFile: "",
+      priDiaVisible: false
+    };
+  },
+  methods: {
+    backPage(){
+      this.$router.push(
+        "/guide?" +
+          "&userid=" +
+          this.userid +
+          "&oid=" +
+          this.oid +
+          "&org=" +
+          this.org
+      );
+    },
+    getData() {
+      let params = {
+        cid: this.cid
+      };
+      this.ajax
+        .get(this.$store.state.api + "selectPblStudentDetail", params)
+        .then(res => {
+          console.log(res);
+          let data = res.data[0][0];
+          if (!!data.chapters) {
+            this.taskList = JSON.parse(data.chapters);
+            console.log('this.taskList',this.taskList);
+
+            this.phase.doPhase = data.doIndex;
+            // if (this.taskList < 5) {
+            //   this.getTaskList(this.taskList);
+            // } else {
+            //   this.Completion = 1;
+            // }
+          } else {
+            console.log("这里这里这里这里这里这里这里这里这里这里");
+            this.selectTopic = data.name;
+            this.getTaskList();
+          }
+        })
+        .catch(err => {
+          // this.isLoading = false;
+          console.error(err);
+        });
+    },
+    changePhase(type, newValue) {
+      this.phase[type] = newValue;
+    },
+    getTaskList(phase = 0) {
+      return new Promise((resolve, reject) => {
+        if (this.loading) return this.$message.info("请稍等");
+        this.loading = true;
+        const _uuid = uuidv4();
+        let _copyTask = JSON.parse(JSON.stringify(this.taskList));
+        if (this.phase.doPhase != 0) {
+          delete _copyTask[this.phase.doPhase - 1].fileList;
+        }
+        const _msg = `
 NOTICE
 Role: 作为学生的学习指导Agent,你熟悉熟悉PBL(基于问题的学习)和5EX教学模型,能够根据学生的学情数据(当前的学习任务设计、学习表现数据、作业数据等)生成自适应的学习任务和对应的5道考核题目。
 Language: Please use the same language as the user requirement, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
@@ -85,7 +182,13 @@ Evaluate(评估):教师和学生共同评估学习效果,反思学习过
 
 ## 学情数据
 选题:${this.selectTopic}
-${this.phase.doPhase==0?'':`这是你生成适应性学习任务时,需要参考的前置学情数据${JSON.stringify(this.taskList[this.phase.doPhase-1])}(当前的学习任务设计、学习表现数据、作业数据等)。`}
+${
+  this.phase.doPhase == 0
+    ? ""
+    : `这是你生成适应性学习任务时,需要参考的前置学情数据${JSON.stringify(
+        _copyTask[this.phase.doPhase - 1]
+      )}(当前的学习任务设计、学习表现数据、作业数据等)。`
+}
 
 # Format example
 {
@@ -111,142 +214,231 @@ ${this.phase.doPhase==0?'':`这是你生成适应性学习任务时,需要参
 }
 
 Instruction: Based on the context, follow "Format example", write content.
-`
-			console.log(_msg)
-			// ${
-			// 	this.phase.doPhase==0?'':`
-			// 	## 学情数据
-			// 	这是你生成适应性学习任务时,需要参考的前置学情数据${JSON.stringify(this.taskList[this.phase.doPhase])}(当前的学习任务设计、学习表现数据、作业数据等)。`
-			// }
-
-			let params = {
-				model: "gpt-3.5-turbo",
-				temperature: 0,
-				max_tokens: 4096,
-				top_p: 1,
-				frequency_penalty: 0,
-				presence_penalty: 0,
-				messages: [{role:"user",content:_msg}],
-				uid: _uuid,
-				mind_map_question: "",
-				stream:false
-			}
-			this.ajax
-			.post("https://gpt4.cocorobo.cn/chat", params)
-			.then((res) => {
-				let _data = res.data.FunctionResponse.choices[0];
-				let content = _data.message.content;
-				console.log(content)
-				content = content.replaceAll('```json','').replaceAll('```','')
-				// console.log(content)
-				const _result = JSON.parse(content);
-				
-				_result.detail = _result.detail?_result.detail:"",
-				_result.steps = _result.steps?_result.steps:"",
-				_result.target = _result.target?_result.target:"",
-				_result.tips =_result.tips?_result.tips:""
-				this.taskList[phase] = _result;
-				// this.phase.doPhase = phase;
-				this.phase.atPhase = phase;
-				console.log(this.taskList)
-				this.loading = false;
-				resolve();
-			})
-			.catch((e) => {
-				this.loading = false;
-				this.$message.error("获取任务失败")
-				if(this.phase.doPhase!=0){
-					this.phase.doPhase--;
-				}
-				resolve();
-				console.log(e);
-			});
-			})
-			
-		},
-		choiceAnswer(_data){
-			this.taskList[this.phase.atPhase].answerArray[_data[0]].userAnswer = _data[1];
-			this.$forceUpdate()
-		},
-		submitTask(){
-			
-			this.loading = true;
-			let sum = 0;
-			this.taskList[this.phase.atPhase].answerArray.forEach(i=>{
-				if('userAnswer' in i){
-					sum++;
-				}
-			})
-			if(sum<this.taskList[this.phase.atPhase].answerArray.length){
-				this.loading = false;
-				return this.$message.error("当前阶段还未完成")
-			}else if((this.phase.doPhase>this.phase.atPhase)){
-				this.loading = false;
-				return this.$message.error("该阶段已经提交过了")
-			}else{
-				this.loading = false;
-				this.phase.doPhase++;
-				if(this.phase.doPhase==5){
-					return this.$message.error('所有阶段已经完成');
-				}
-				this.getTaskList(this.phase.doPhase)
-			}
-		},
-		selectTopicSuccess(_form){
-			if(_form.title){
-					this.phase = {
-					doPhase:0,
-					atPhase:0,
-				}
-				this.selectTopic = _form.title;
-				this.getTaskList()
-				this.$refs.selectTopicDialogRef.close();
-			}
-		}
-	},
-	mounted() {
-		
-		this.selectTopic = "";
-		this.$refs.selectTopicDialogRef.open();
-		// this.getTaskList()
-	},
+`;
+        // console.log(_msg);
+        // ${
+        // 	this.phase.doPhase==0?'':`
+        // 	## 学情数据
+        // 	这是你生成适应性学习任务时,需要参考的前置学情数据${JSON.stringify(this.taskList[this.phase.doPhase])}(当前的学习任务设计、学习表现数据、作业数据等)。`
+        // }
+
+        let params = {
+          model: "gpt-3.5-turbo",
+          temperature: 0,
+          max_tokens: 4096,
+          top_p: 1,
+          frequency_penalty: 0,
+          presence_penalty: 0,
+          messages: [{ role: "user", content: _msg }],
+          uid: _uuid,
+          mind_map_question: "",
+          stream: false
+        };
+        this.ajax
+          .post("https://gpt4.cocorobo.cn/chat", params)
+          .then(res => {
+            let _data = res.data.FunctionResponse.choices[0];
+            let content = _data.message.content;
+            // console.log(content);
+            content = content.replaceAll("```json", "").replaceAll("```", "");
+            // console.log(content)
+            const _result = JSON.parse(content);
+
+            (_result.detail = _result.detail ? _result.detail : ""),
+              (_result.steps = _result.steps ? _result.steps : ""),
+              (_result.target = _result.target ? _result.target : ""),
+              (_result.tips = _result.tips ? _result.tips : "");
+            _result.fileList = [];
+            this.taskList[phase] = _result;
+            // this.phase.doPhase = phase;
+            this.phase.atPhase = phase;
+            console.log(this.taskList);
+            this.saveTopic();
+            this.savaDoIndex();
+            this.loading = false;
+            resolve();
+          })
+          .catch(e => {
+            this.loading = false;
+            this.$message.error("获取任务失败");
+            if (this.phase.doPhase != 0) {
+              this.phase.doPhase--;
+            }
+            resolve();
+            console.log(e);
+          });
+      });
+    },
+    choiceAnswer(_data) {
+      this.taskList[this.phase.atPhase].answerArray[_data[0]].userAnswer =
+        _data[1];
+      this.$forceUpdate();
+    },
+    savaDoIndex() {
+      let params = [
+        {
+          cid: this.cid,
+          doi: this.phase.doPhase
+        }
+      ];
+      this.ajax
+        .post(this.$store.state.api + "updatePblStudentDoIndex", params)
+        .then(res => {
+          console.log(res);
+        });
+    },
+    saveTopic() {
+      let params = [
+        {
+          cid: this.cid,
+          chapters: JSON.stringify(this.taskList)
+        }
+      ];
+      this.ajax
+        .post(this.$store.state.api + "updatePblStudentChapters", params)
+        .then(res => {
+          console.log(res);
+        });
+    },
+
+    submitTask() {
+      this.loading = true;
+      let sum = 0;
+      this.taskList[this.phase.atPhase].answerArray.forEach(i => {
+        if ("userAnswer" in i) {
+          sum++;
+        }
+      });
+      if (sum < this.taskList[this.phase.atPhase].answerArray.length) {
+        this.loading = false;
+        return this.$message.error("当前阶段还未完成");
+      } else if (this.phase.doPhase > this.phase.atPhase) {
+        this.loading = false;
+        return this.$message.error("该阶段已经提交过了");
+      } else {
+        this.loading = false;
+        this.phase.doPhase++;
+        if (this.Completion == 0) {
+          this.saveTopic();
+          this.savaDoIndex();
+        }
+        if (this.phase.doPhase == 5) {
+          this.Completion = 1;
+          return this.$message("所有阶段已经完成");
+        }
+        this.getTaskList(this.phase.doPhase);
+      }
+    },
+    selectTopicSuccess(_form) {
+      if (_form.title) {
+        this.phase = {
+          doPhase: 0,
+          atPhase: 0
+        };
+        this.selectTopic = _form.title;
+        this.getTaskList();
+        this.$refs.selectTopicDialogRef.close();
+      }
+    },
+    handleClose(done) {
+      this.priFile = "";
+
+      done();
+      this.$forceUpdate()
+
+      // this.$confirm('确认关闭?')
+      //   .then(_ => {
+      //     done();
+      //   })
+      //   .catch(_ => {});
+    },
+    previewImg(url) {
+      this.$hevueImgPreview(url)
+    },
+    lookFile(url) {
+
+      this.priFile = "";
+      this.$forceUpdate()
+
+      this.priFile = url;
+
+      this.priDiaVisible = true;
+      // console.log(/\.(jpeg|jpg|png|img)$/i.test(url));
+      // console.log(/\.(xlsx|doc|docx)$/i.test(url));
+      // const path = require('path');
+      // return path.extname(url).toLowerCase().slice(1); // 获取后缀并去掉点(.)
+    },
+    addFile(obj) {
+      this.taskList[this.phase.atPhase].fileList.push(obj);
+      this.$forceUpdate();
+    },
+    deleteFile(index) {
+      this.taskList[this.phase.atPhase].fileList.splice(index, 1);
+      this.$forceUpdate();
+    }
+  },
+  mounted() {
+    this.getData();
+    // this.selectTopic = "";
+    // this.$refs.selectTopicDialogRef.open();
+    // this.getTaskList()
+  }
 };
 </script>
 
 <style scoped>
 .pblCourse {
-	min-width: 1500px;
-	/* min-height: 800px; */
-	width: 100%;
-	height: 100vh;
-	display: flex;
-	background-color: #f0f2f5;
-	box-sizing: border-box;
-	padding: 20px;
+  min-width: 1500px;
+  /* min-height: 800px; */
+  width: 100%;
+  height: 100vh;
+  display: flex;
+  background-color: #f0f2f5;
+  box-sizing: border-box;
+  padding: 20px;
+  background-image: radial-gradient(#c6d6ff, #d0d1fe, #f3f7ff);
+}
+.pblCourse >>> .el-dialog{
+  height: 900px;margin-top: 5vh !important;
+  width: 1100px;
+}
+.pblCourse >>> .el-dialog__body{
+  height: 700px !important;
+  display: flex;
+  justify-content: center;
+}
+.BackBtn{
+  position: absolute;
+  top: 20px;
+  right: 10px;
+  border-radius: 30px;
+  padding: 5px 15px;
+  background-color: #fff;
+	border: 2px solid #c8aeff;
+  cursor: pointer;
 }
-
 .pc_left {
-	width: calc(100% - 500px - 20px);
-	margin-right: 20px;
-	box-sizing: border-box;
+  width: calc(100% - 500px - 20px);
+  margin-right: 20px;
+  box-sizing: border-box;
 }
 
 .pc_l_top {
-	width: 100%;
-	height: 150px;
-	box-sizing: border-box;
+  width: 100%;
+  height: 150px;
+  box-sizing: border-box;
 }
 
 .pc_l_bottom {
-	width: 100%;
-	height: calc(100% - 150px - 15px);
-	box-sizing: border-box;
-	margin-top: 15px;
+  width: 100%;
+  height: calc(100% - 150px - 15px);
+  box-sizing: border-box;
+  margin-top: 15px;
 }
 
 .pc_right {
-	width: 500px;
-	height: 100%;
-	box-sizing: border-box;
+  width: 500px;
+  height: 100%;
+  box-sizing: border-box;
 }
 </style>

+ 23 - 1
src/components/pages/test/add/components/checkOrder.vue

@@ -105,6 +105,12 @@
                                         :cJson="cJson" @setJson="setJson">
                                     </evaDialog>
                                 </div>
+                                <div v-if="item3.type == 8">
+                                    <timeX :cJson="item3.json"></timeX>
+                                    <timeDialog v-if="item3.type == 8 && checkC === `x${index1}-${index2}-${index3}`"
+                                        :cJson="cJson" @setJson="setJson">
+                                    </timeDialog>
+                                </div>
                             </div>
                         </div>
                     </div>
@@ -135,6 +141,11 @@
                             <evaDialog v-if="item2.type == 7 && checkC === `x${index1}-${index2}`" :cJson="cJson"
                                 @setJson="setJson"></evaDialog>
                         </div>
+                        <div v-else-if="item2.type == 8">
+                            <timeX :cJson="item2.json"></timeX>
+                            <timeDialog v-if="item2.type == 8 && checkC === `x${index1}-${index2}`" :cJson="cJson"
+                                @setJson="setJson"></timeDialog>
+                        </div>
                     </div>
                 </div>
             </div>
@@ -164,6 +175,11 @@
                     <evaDialog v-if="item1.type == 7 && checkC === `x${index1}`" :cJson="cJson" @setJson="setJson">
                     </evaDialog>
                 </div>
+                <div v-else-if="item1.type == 8">
+                    <timeX :cJson="item1.json"></timeX>
+                    <timeDialog v-if="item1.type == 8 && checkC === `x${index1}`" :cJson="cJson" @setJson="setJson">
+                    </timeDialog>
+                </div>
             </div>
         </div>
         <el-dialog title="修改名称" :visible.sync="groupDaliog" :append-to-body="true" width="500px"
@@ -199,6 +215,8 @@ import courseDialog from './course/index.vue'
 import courseX from './course/course.vue'
 import evaDialog from './evaBox/index.vue'
 import evaX from './evaBox/eva.vue'
+import timeDialog from './timeBox/index.vue'
+import timeX from './timeBox/time.vue'
 export default {
     mixins: [minxinVue],
     components: {
@@ -212,6 +230,8 @@ export default {
         courseX,
         evaDialog,
         evaX,
+        timeDialog,
+        timeX
     },
     props: {
         checkJson: {
@@ -232,7 +252,7 @@ export default {
         return {
             manualJson: [],
             isdrag: "",
-            canEdit: [1, 3, 5, 6, 7],
+            canEdit: [1, 3, 5, 6, 7, 8],
             ctype: "",
             dragType: "",
             oldIndex: "",
@@ -265,6 +285,8 @@ export default {
                         className += " test_course_file"
                     } else if (item.type == 7) {
                         className += " test_eva_file"
+                    } else if (item.type == 8) {
+                        className += " test_icon_time"
                     }
                     return index + 1 + "、" + (item.json && this.etype != 'edit' ? `<span class='${className}'></span>` : `<span class='${className}'></span>` + this.options2[item.type]) + (item.json && this.etype != 'edit' ? `${item.json.title}` : "");
                 } else if (item.ttype == 2) {

+ 192 - 0
src/components/pages/test/add/components/timeBox/index.vue

@@ -0,0 +1,192 @@
+<template>
+    <div class="choice_box jiao" @click.stop="">
+        <!-- <div class="title">设置附件</div> -->
+        <div class="box">
+            <div class="set_title">
+                <span>表单问题:</span>
+                <textarea v-autoHeight="68" rows="2" class="binfo_input binfo_textarea" cols v-model="checkJson.title"
+                    placeholder=""></textarea>
+            </div>
+            <div class="set_title">
+                <span>问题描述:</span>
+                <textarea v-autoHeight="68" rows="2" class="binfo_input binfo_textarea" cols v-model="checkJson.detail"
+                    placeholder="请输入描述"></textarea>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+// import EditorBar from "../../../../../tools/wangEnduit";
+export default {
+    components: {
+        // EditorBar,
+    },
+    props: {
+        cJson: {
+            type: Object,
+        },
+    },
+    data() {
+        return {
+            ctype: 1,
+            options: [
+                { type: 1, name: '附件' },
+                // { type: 2, name: '多选题' }
+            ],
+            checkJson: {}
+        }
+    },
+    directives: {
+        autoHeight: {
+            update(el, binding) {
+                const { value } = binding
+                if (value && typeof value === 'number') {
+                    el.style.height = `${value}px`
+                } else {
+                    el.style.height = 'auto'
+                }
+            },
+            componentUpdated(el) {
+                el.style.height = `${el.scrollHeight + 5}px`
+            },
+        },
+    },
+    watch: {
+        checkJson: {
+            handler(newVal) {
+                this.$emit("setJson", newVal)
+            },
+            deep: true
+        }
+    },
+    methods: {
+        depthCopy(s) {
+            return JSON.parse(JSON.stringify(s));
+        },
+        changeAnswer() {
+            this.checkJson.answer = []
+        },
+        change(val) {
+            this.checkJson.title = val
+            this.$forceUpdate();
+            console.log(val);
+        },
+
+    },
+    mounted() {
+        console.log(1);
+        // console.log(this.cJson);
+        if (!this.cJson) {
+            this.checkJson = {
+                title: "标题",
+                detail: "",
+            };
+        } else {
+            this.checkJson = this.depthCopy(this.cJson);
+        }
+
+    },
+}
+</script>
+
+<style scoped>
+.choice_box {
+    margin-top: 10px;
+    width: 100%;
+    background: #f5f6f7;
+    padding: 10px 10px 10px 36px;
+    box-sizing: border-box;
+    position: relative;
+}
+
+.choice_box>.box {}
+
+.set_type {
+    margin-top: 10px;
+    display: flex;
+    align-items: center;
+}
+
+.set_title {
+    margin-top: 10px;
+    display: flex;
+    align-items: flex-start;
+    /* flex-direction: column; */
+}
+
+.set_type>span,
+.set_title>span {
+    min-width: fit-content;
+    font-size: 15px;
+    min-width: 90px;
+    text-align: right;
+}
+
+.set_options {
+    margin-top: 10px;
+}
+
+.set_options>.title {
+    font-size: 15px;
+}
+
+.xuan_body {
+    margin-top: 10px;
+    font-size: 14px;
+}
+
+.binfo_input {
+    width: 100%;
+    margin: 0;
+    padding: 12px 14px;
+    display: block;
+    min-width: 0;
+    outline: none;
+    box-sizing: border-box;
+    background: none;
+    border: none;
+    border-radius: 4px;
+    background: #fff;
+    font-size: 16px;
+    resize: none;
+    font-family: 'Microsoft YaHei';
+    min-height: 48px;
+    /* border: 1px solid #3682fc00; */
+    border: 1px solid #CAD1DC;
+}
+
+.binfo_textarea {
+    border: 1px solid #CAD1DC;
+    font-size: 16px;
+    resize: none;
+    /* background: #f6f6f6; */
+    font-family: 'Microsoft YaHei';
+}
+
+.binfo_input:focus-visible {
+    border: 1px solid #3681FC !important;
+}
+
+
+.set_title > .number{
+    display: flex;
+    align-items: center;
+}
+
+.set_title > .number > span{
+    margin: 0 10px;
+}
+/* .jiao::before{
+    content: '';
+    position: absolute;
+    width: 0px;
+    height: 0px;
+    top: -20px;
+    left: 15px;
+    border-left: 12px solid transparent;
+    border-right: 12px solid transparent;
+    border-bottom: 10px solid #f6f6f6;
+    border-top: 10px solid transparent;
+} */
+</style>

+ 98 - 0
src/components/pages/test/add/components/timeBox/time.vue

@@ -0,0 +1,98 @@
+<template>
+    <div class="c_box">
+        <div class="mask"></div>
+        <div class="choice_box">
+            <div class="title" style="display: flex;">
+                <span>{{cJson.title }}</span>
+            </div>
+            <div class="detail" v-if="cJson.detail">{{ cJson.detail }}</div>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    props: {
+        cJson: {
+            type: Object,
+        },
+    },
+    data() {
+        return {
+            option: {
+                1: { name: '附件' },
+                // 2: { name: '多选题' }
+            }
+        }
+    },
+}
+</script>
+
+<style scoped>
+.c_box {
+    width: calc(100% - 20px);
+    position: relative;
+    margin: 0 auto;
+    padding-left: 26px;
+    box-sizing: border-box;
+}
+
+.mask {
+    position: absolute;
+    height: 100%;
+    width: 100%;
+    z-index: 2;
+}
+
+.choice_box {
+    white-space: pre-line;
+}
+
+.choice_box>.title {
+    font-weight: bold;
+    width: 100%;
+    word-break: break-all;
+}
+
+.choice_box>.detail {
+    width: 100%;
+    word-break: break-all;
+    color: rgb(136, 139, 146);
+    margin: 10px 0 0;
+}
+
+.choice_box>.choices {
+    margin-top: 10px;
+}
+
+.binfo_input {
+    width: 100%;
+    margin: 0;
+    padding: 10px;
+    display: block;
+    min-width: 0;
+    outline: none;
+    box-sizing: border-box;
+    background: none;
+    border: none;
+    border-radius: 5px;
+    background: #fff;
+    font-size: 16px;
+    resize: none;
+    font-family: 'Microsoft YaHei';
+    min-height: 120px;
+    /* border: 1px solid #3682fc00; */
+    border: 1.5px solid #e0e0e0;
+}
+
+.binfo_input>div {
+    border: 1.5px dashed #dfdfdf;
+    height: 120px;
+    width: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background: rgb(249, 250, 251);
+    color: rgb(124, 124, 124);
+    border-radius: 5px;
+}</style>

+ 1 - 1
src/components/pages/test/add/edit/check/eva.vue

@@ -107,7 +107,7 @@ export default {
     flex-wrap: wrap;
     justify-content: center;
     width: 90%;
-    margin: 0 auto;
+    margin: 10px auto 0;
 }
 
 .choices > .score{

+ 15 - 3
src/components/pages/test/add/edit/check/index.vue

@@ -12,6 +12,7 @@
             <fileV :tindex="index" :cJson.sync="item.json" v-if="item.type == 5"></fileV>
             <courseV :tindex="index" :cJson.sync="item.json" v-if="item.type == 6"></courseV>
             <evaV :tindex="index" :cJson.sync="item.json" v-if="item.type == 7"></evaV>
+            <timeV :tindex="index" :cJson.sync="item.json" v-if="item.type == 8"></timeV>
             <span v-else>暂未设置题目</span>
           </div>
           <div v-for="(item2, index2) in item.array" :key="`${index}-${index2}`" class="check_box_xia">
@@ -22,6 +23,7 @@
               <fileV :tindex="index2" :cJson.sync="item2.json" v-if="item2.type == 5"></fileV>
               <courseV :tindex="index2" :cJson.sync="item2.json" v-if="item2.type == 6"></courseV>
               <evaV :tindex="index2" :cJson.sync="item2.json" v-if="item2.type == 7"></evaV>
+              <timeV :tindex="index2" :cJson.sync="item2.json" v-if="item2.type == 8"></timeV>
               <!-- <span v-else>暂未设置题目</span> -->
             </div>
           </div>
@@ -36,6 +38,7 @@
             <fileV :tindex="index" :cJson.sync="item.json" v-if="item.type == 5"></fileV>
             <courseV :tindex="index" :cJson.sync="item.json" v-if="item.type == 6"></courseV>
             <evaV :tindex="index" :cJson.sync="item.json" v-if="item.type == 7"></evaV>
+            <timeV :tindex="index" :cJson.sync="item.json" v-if="item.type == 8"></timeV>
             <!-- <span v-else>暂未设置题目</span> -->
           </div>
           <div v-for="(item2, index2) in item.array" :key="`${index}-${index2}`" class="check_box_xia">
@@ -46,6 +49,7 @@
               <fileV :tindex="index2" :cJson.sync="item2.json" v-if="item2.type == 5"></fileV>
               <courseV :tindex="index2" :cJson.sync="item2.json" v-if="item2.type == 6"></courseV>
               <evaV :tindex="index2" :cJson.sync="item2.json" v-if="item2.type == 7"></evaV>
+              <timeV :tindex="index2" :cJson.sync="item2.json" v-if="item2.type == 8"></timeV>
               <!-- <span v-else>暂未设置题目</span> -->
             </div>
           </div>
@@ -68,6 +72,7 @@ import gapV from './gap.vue';
 import fileV from './file.vue';
 import courseV from './course.vue';
 import evaV from './eva.vue';
+import timeV from './time.vue';
 export default {
   props: {
     cJson: {
@@ -83,6 +88,7 @@ export default {
     fileV,
     courseV,
     evaV,
+    timeV
   },
   data() {
     return {
@@ -169,21 +175,25 @@ export default {
         let checkArray = _json.filter(item => {
           if (item.array) {
             item.array = item.array.filter((item2) => {
-              if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.type != 6 && item.type != 7) {
+              if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.type != 6 && item.type != 7 && item.type != 8) {
                 item2.json.answer2 = [];
               } else if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.type == 6) {
                 item2.json.answer2 = item2.json.courses[0];
               } else if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.type == 7) {
                 item2.json.answer2 = '';
+              } else if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.type == 8) {
+                item2.json.answer2 = '';
               }
               if (item2.array) {
                 item2.array = item2.array.filter((item3) => {
-                  if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.type != 6 && item3.type != 7) {
+                  if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.type != 6 && item3.type != 7 && item3.type != 8) {
                     item3.json.answer2 = [];
                   } else if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.type == 6) {
                     item3.json.answer2 = item3.json.courses[0];
                   } else if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.type == 7) {
                     item3.json.answer2 = '';
+                  } else if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.type == 8) {
+                    item3.json.answer2 = '';
                   }
                   return item3;
                 });
@@ -193,12 +203,14 @@ export default {
               );
             });
           }
-          if (item.ttype == 1 && item.json && !item.json.answer2 && item.type != 6 && item.type != 7) {
+          if (item.ttype == 1 && item.json && !item.json.answer2 && item.type != 6 && item.type != 7 && item.type != 8) {
             item.json.answer2 = [];
           } else if (item.ttype == 1 && item.json && !item.json.answer2 && item.type == 6) {
             item.json.answer2 = item.json.courses[0];
           } else if (item.ttype == 1 && item.json && !item.json.answer2 && item.type == 7) {
             item.json.answer2 = '';
+          } else if (item.ttype == 1 && item.json && !item.json.answer2 && item.type == 8) {
+            item.json.answer2 = '';
           }
           console.log(item.array);
           return (item.ttype != 1 && item.array.length > 0) || item.ttype == 1;

+ 103 - 0
src/components/pages/test/add/edit/check/time.vue

@@ -0,0 +1,103 @@
+<template>
+    <div class="c_box">
+        <div class="choice_box">
+            <div class="title" style="display: flex;">
+                <span style="min-width: fit-content;">{{ tindex + 1 + "、" }}</span>
+                <span>{{ checkJson.title }}</span>
+            </div>
+            <div class="detail" v-if="checkJson.detail" v-html="checkJson.detail"
+                style="color: #00000099;margin-top: 5px;">
+            </div>
+            <div style="margin-top: 10px;">
+                <el-date-picker
+                    v-model="checkJson.answer2"
+                    type="date"
+                    format="yyyy 年 MM 月 dd 日"
+                    value-format="yyyy年MM月dd日"
+                    placeholder="年/月/日">
+                </el-date-picker>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+
+export default {
+    props: {
+        tindex: {
+            type: Number
+        },
+        cJson: {
+            type: Object,
+        },
+        checktype: {
+            type: Number,
+            default: 1
+        },
+        see: {
+            type: Boolean,
+            default: false
+        }
+    },
+    data() {
+        return {
+            option: {
+                1: { name: '附件' },
+            },
+            userid: this.$route.query.userid,
+            checkJson: undefined,
+            progress: 0,
+            isFinishSize: 0,
+            proVisible: false,
+            isAllSize: 0,
+            wurl: "",
+            isTong: false
+        }
+    },
+    watch: {
+        checkJson: {
+            handler(newValue) {
+                this.$emit('update:cJson', newValue)
+            },
+            deep: true
+        },
+    },
+    methods: {
+        depthCopy(s) {
+            return JSON.parse(JSON.stringify(s));
+        },
+
+    },
+    mounted() {
+        this.checkJson = this.cJson ? this.depthCopy(this.cJson) : undefined
+
+    }
+}
+</script>
+
+<style scoped>
+.c_box {
+    width: 100%;
+    position: relative;
+}
+
+/* .mask {
+    position: absolute;
+    height: 100%;
+    width: 100%;
+    z-index: 2;
+} */
+
+.choice_box {
+    white-space: pre-line;
+}
+
+.choice_box>.title {
+    font-weight: bold;
+    width: 100%;
+    word-break: break-all;
+}
+
+
+</style>

+ 12 - 1
src/components/pages/test/add/edit/edit/index.vue

@@ -23,9 +23,10 @@
                   pub_test_btn_file: item.value == 5,
                   pub_test_btn_course: item.value == 6,
                   pub_test_btn_eva: item.value == 7,
+                  pub_test_btn_time: item.value == 8,
                 }"
               >
-                {{ item.label }}
+                {{ item.label }} 
               </button>
             </div>
           </div>
@@ -245,6 +246,11 @@ export default {
             small: 0,
             big: 10,
           };
+        } else if (topicType == 8) {
+          json.json = {
+            title: "标题",
+            detail: "",
+          };
         }
         if (_json.array) {
           if (type == 3 && _check.length == 2) {
@@ -326,6 +332,11 @@ export default {
               small: 0,
               big: 10,
             };
+          } else if (topicType == 8) {
+            json1.json = {
+              title: "标题",
+              detail: "",
+            };
           }
           this.manualJson.push(json1);
           this.$forceUpdate()

+ 5 - 0
src/components/pages/test/add/minxins/minxin.js

@@ -30,6 +30,10 @@ const minxin = {
           value: 7,
           label: "评分"
         },
+        {
+          value: 8,
+          label: "日期"
+        },
       ],
       optionsPin:[
        {
@@ -45,6 +49,7 @@ const minxin = {
         5: "附件",
         6: "课程",
         7: "评分",
+        8: "日期",
       },
       buttonOptions: [
         { name: "分组", type: 1 },

+ 10 - 0
src/components/pages/test/add/setInfo/manualCreated.vue

@@ -208,6 +208,11 @@ export default {
             small: 0,
             big: 10,
           };
+        } else if (this.topicType == 8) {
+          json.json = {
+            title: "标题",
+            detail: "",
+          };
         }
         if (_json.array) {
           if (type == 3 && _check.length == 2) {
@@ -305,6 +310,11 @@ export default {
                 small: 0,
                 big: 10,
               };
+            } else if (this.topicType == 8) {
+              json1.json = {
+                title: "标题",
+                detail: "",
+              };
             }
             this.checkJson.push(json1);
           }

+ 42 - 4
src/components/pages/test/check/index.vue

@@ -92,7 +92,7 @@
               <div class="title">
                 <el-tooltip :content="selectType(item)" placement="top" effect="dark">
                   <span class="test_icon"
-                    :class="{ test_icon_check: item.type == 1 && item.atype == 2, test_icon_checkO: item.type == 1 && item.atype == 1, test_icon_gap: item.type == 3, test_icon_file: item.type == 5, test_course_file: item.type == 6, test_eva_file: item.type == 7 }"></span>
+                    :class="{ test_icon_check: item.type == 1 && item.atype == 2, test_icon_checkO: item.type == 1 && item.atype == 1, test_icon_gap: item.type == 3, test_icon_file: item.type == 5, test_course_file: item.type == 6, test_eva_file: item.type == 7,test_icon_time: item.type == 8 }"></span>
                 </el-tooltip>
                 <span>{{ item.title }}</span>
 								<el-button v-if="item.type == 5 && item.array.length>0" class="title_downBtn" type="primary" size="small" @click.stop="downloadFileType5(item.array,item.title)">批量下载附件</el-button>
@@ -216,6 +216,28 @@
                   <checkPie :dataJ="item.array"></checkPie>
                 </div>
               </div>
+              <div class="content2" v-if="item.type == 8">
+                <div class="left">
+                  <div class="title">
+                    <span>序号</span>
+                    <span>词频</span>
+                    <span>日期</span>
+                  </div>
+                  <div class="data" v-for="(data, index2) in item.array" :key="index + '-' + index2">
+                    <span>{{ index2 + 1 }}</span>
+                    <span>{{ data.count }}次</span>
+                    <el-tooltip :content="data.name" placement="top" effect="dark">
+                      <!-- content to trigger tooltip here -->
+                      <span>{{ data.name }}</span>
+                    </el-tooltip>
+                  </div>
+                </div>
+                <div class="right">
+                  <wordcloud :data="item.array" nameKey="name" valueKey="count" :showTooltip="false"
+                    :wordClick="wordClickHandler">
+                  </wordcloud>
+                </div>
+              </div>
             </div>
           </div>
           <div class="table_content" v-if="stype == 2">
@@ -244,7 +266,7 @@
                     <span class="answer_type" v-for="(answer2, index2) in scope.row.array[index].json.answer2"
                       :key="index + '-' + index2">{{ scope.row.array[index].json.array[answer2].option }}</span>
                   </div>
-                  <div v-if="scope.row.array[index].type == 3" style="display: flex; flex-wrap: wrap;">
+                  <div v-if="scope.row.array[index].type == 3 || scope.row.array[index].type == 8" style="display: flex; flex-wrap: wrap;">
                     {{ scope.row.array[index].json.answer2 }}
                   </div>
                   <div v-if="scope.row.array[index].type == 5" style="display: flex; flex-wrap: wrap;"
@@ -481,6 +503,8 @@ export default {
           return '课程'
         } else if (item.type == 7) {
           return '评分'
+        } else if (item.type == 8) {
+          return '日期'
         }
       };
     }
@@ -700,7 +724,7 @@ export default {
                   topic.array[_answer[k]].count++
                   topic.count++
                 }
-              } else if (topic.type == 3) {
+              } else if (topic.type == 3 || topic.type == 8) {
                 let type3 = 1
                 let _answer = el2.array[i].json.answer2
                 if (_answer) {
@@ -1056,6 +1080,9 @@ export default {
             let _score = this.getScore2(item.json)
             let _option = `<div style='margin:10px 0 0 40px;'>打分:${_score}分</div>`
             _test += _option
+        } else if (item.type == 8 && item.json.answer2) {
+          let _option = `<div style='margin:10px 0 0 40px;'>${item.json.answer2}</div>`
+          _test += _option
         }
       }
       _test += `</div>`
@@ -1099,7 +1126,10 @@ export default {
             let _score = this.getScore2(item.json)
             let _option = `<div style='margin:10px 0 0 40px;'>打分:${_score}分</div>`
             _test += _option
-        }
+        } else if (item.type == 8 && item.json.answer2) {
+          let _option = `<div style='margin:10px 0 0 40px;'>${item.json.answer2}</div>`
+          _test += _option
+        } 
       }
       _test += `</div>`
       let _html = _title + _content + _detail + _test;
@@ -1175,6 +1205,9 @@ export default {
             let _score = this.getScore2(item.json)
             let _option = `<div style='margin:10px 0 0 40px;'>打分:${_score}分</div>`
             _test += _option
+        } else if (item.type == 8 && item.json.answer2) {
+          let _option = `<div style='margin:10px 0 0 40px;'>${item.json.answer2}</div>`
+          _test += _option
         }
       }
       _test += `</div>`
@@ -1219,6 +1252,9 @@ export default {
             let _score = this.getScore2(item.json)
             let _option = `<div style='margin:10px 0 0 40px;'>打分:${_score}分</div>`
             _test += _option
+        } else if (item.type == 8 && item.json.answer2) {
+          let _option = `<div style='margin:10px 0 0 40px;'>${item.json.answer2}</div>`
+          _test += _option
         }
       }
       _test += `</div>`
@@ -1354,6 +1390,8 @@ export default {
           } else if (res[i].array[j].type == 7 && res[i].array[j].json.answer2) {
             let _score = this.getScore2(res[i].array[j].json)
             _json[j + 1 + "." + chapters[j].json.title] = _score
+          } else if (res[i].array[j].type == 8 && res[i].array[j].json.answer2) {
+            _json[j + 1 + "." + chapters[j].json.title] = res[i].array[j].json.answer2
           }
         }
         array.push(_json);

+ 1 - 1
src/components/pages/testStudent/view/component/eva.vue

@@ -116,7 +116,7 @@ export default {
     flex-wrap: wrap;
     justify-content: center;
     width: 90%;
-    margin: 0 auto;
+    margin: 10px auto 0;
 }
 
 .choices > .score{

+ 105 - 0
src/components/pages/testStudent/view/component/time.vue

@@ -0,0 +1,105 @@
+<template>
+    <div class="c_box">
+        <div class="choice_box">
+            <div class="title" style="display: flex;">
+                <span style="min-width: fit-content;">{{ tindex + 1 + "、" }}</span>
+                <span>{{ checkJson.title }}</span>
+            </div>
+            <div class="detail" v-if="checkJson.detail" v-html="checkJson.detail"
+                style="color: #00000099;margin-top: 5px;">
+            </div>
+            <div style="margin-top: 10px;">
+                <el-date-picker
+                    :readonly="checktype == 2"
+                    v-model="checkJson.answer2"
+                    type="date"
+                    format="yyyy 年 MM 月 dd 日"
+                    value-format="yyyy年MM月dd日"
+                    placeholder="年/月/日">
+                </el-date-picker>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+
+export default {
+    props: {
+        tindex: {
+            type: Number
+        },
+        cJson: {
+            type: Object,
+        },
+        checktype: {
+            type: Number,
+            default: 1
+        },
+        see: {
+            type: Boolean,
+            default: false
+        }
+    },
+    data() {
+        return {
+            option: {
+                1: { name: '附件' },
+            },
+            userid: this.$route.query.userid,
+            checkJson: undefined,
+            progress: 0,
+            isFinishSize: 0,
+            proVisible: false,
+            isAllSize: 0,
+            wurl: "",
+            isTong: false
+        }
+    },
+    watch: {
+        checkJson: {
+            handler(newValue) {
+                this.$emit('update:cJson', newValue)
+            },
+            deep: true
+        },
+    },
+    methods: {
+        depthCopy(s) {
+            return JSON.parse(JSON.stringify(s));
+        },
+
+    },
+    mounted() {
+        this.checkJson = this.cJson ? this.depthCopy(this.cJson) : undefined
+
+    }
+}
+</script>
+
+<style scoped>
+.c_box {
+    width: 100%;
+    position: relative;
+    overflow: unset;
+}
+
+/* .mask {
+    position: absolute;
+    height: 100%;
+    width: 100%;
+    z-index: 2;
+} */
+
+.choice_box {
+    white-space: pre-line;
+}
+
+.choice_box>.title {
+    font-weight: bold;
+    width: 100%;
+    word-break: break-all;
+}
+
+
+</style>

+ 20 - 4
src/components/pages/testStudent/view/component/topic.vue

@@ -23,6 +23,8 @@
               :see="see" :isTeacher="isTeacher" @getTestWorkByCid="getTestWorkByCid" @publish2="publish2" :issetPage.sync="issetPage" :tid="tid"></courseV>
             <evaV :tindex="index" :cJson.sync="item.json" :checktype="checktype" v-else-if="item.type == 7" :see="see"
               :isTeacher="isTeacher"></evaV>
+            <timeV :tindex="index" :cJson.sync="item.json" :checktype="checktype" v-else-if="item.type == 8" :see="see"
+              :isTeacher="isTeacher"></timeV>
             <!-- <span v-else>暂未设置题目</span> -->
           </div>
           <div v-for="(item2, index2) in item.array" :key="`${index}-${index2}`" class="check_box_xia">
@@ -39,6 +41,8 @@
                 :see="see" :isTeacher="isTeacher" @getTestWorkByCid="getTestWorkByCid" @publish2="publish2" :issetPage.sync="issetPage" :tid="tid"></courseV>
               <evaV :tindex="index2" :cJson.sync="item2.json" :checktype="checktype" v-else-if="item2.type == 7"
                 :see="see" :isTeacher="isTeacher"></evaV>
+              <timeV :tindex="index2" :cJson.sync="item2.json" :checktype="checktype" v-else-if="item2.type == 8"
+                :see="see" :isTeacher="isTeacher"></timeV>
               <!-- <span v-else>暂未设置题目</span> -->
             </div>
           </div>
@@ -59,6 +63,8 @@
               :see="see" :isTeacher="isTeacher" @getTestWorkByCid="getTestWorkByCid" @publish2="publish2" :issetPage.sync="issetPage" :tid="tid"></courseV>
             <evaV :tindex="index" :cJson.sync="item.json" :checktype="checktype" v-else-if="item.type == 7" :see="see"
               :isTeacher="isTeacher"></evaV>
+            <timeV :tindex="index" :cJson.sync="item.json" :checktype="checktype" v-else-if="item.type == 8" :see="see"
+              :isTeacher="isTeacher"></timeV>
             <!-- <span v-else>暂未设置题目</span> -->
           </div>
           <div v-for="(item2, index2) in item.array" :key="`${index}-${index2}`" class="check_box_xia">
@@ -75,6 +81,8 @@
                 :see="see" :isTeacher="isTeacher" @getTestWorkByCid="getTestWorkByCid" @publish2="publish2" :issetPage.sync="issetPage" :tid="tid"></courseV>
               <evaV :tindex="index2" :cJson.sync="item2.json" :checktype="checktype" v-else-if="item2.type == 7"
                 :see="see" :isTeacher="isTeacher"></evaV>
+              <timeV :tindex="index2" :cJson.sync="item2.json" :checktype="checktype" v-else-if="item2.type == 8"
+                :see="see" :isTeacher="isTeacher"></timeV>
               <!-- <span v-else>暂未设置题目</span> -->
             </div>
           </div>
@@ -99,6 +107,7 @@ import gapV from './gap.vue';
 import fileV from './file.vue';
 import courseV from './course.vue';
 import evaV from './eva.vue';
+import timeV from './time.vue';
 export default {
   props: {
     cJson: {
@@ -140,7 +149,8 @@ export default {
     gapV,
     fileV,
     courseV,
-    evaV
+    evaV,
+    timeV
   },
   data() {
     return {
@@ -251,21 +261,25 @@ export default {
         let checkArray = _json.filter((item) => {
           if (item.array) {
             item.array = item.array.filter((item2) => {
-              if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.type != 6 && item.type != 7) {
+              if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.type != 6 && item.type != 7 && item.type != 8) {
                 item2.json.answer2 = [];
               } else if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.type == 6) {
                 item2.json.answer2 = this.gcourseid ? this.gcourseid : item2.json.courses[0];
               } else if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.json.answer2 !== 0 && item2.type == 7) {
                 item2.json.answer2 = '';
+              } else if (item2.ttype == 1 && item2.json && !item2.json.answer2 && item2.json.answer2 !== 0 && item2.type == 8) {
+                item2.json.answer2 = '';
               }
               if (item2.array) {
                 item2.array = item2.array.filter((item3) => {
-                  if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.type != 6 && item3.type != 7) {
+                  if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.type != 6 && item3.type != 7 && item3.type != 8) {
                     item3.json.answer2 = [];
                   } else if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.type == 6) {
                     item3.json.answer2 = this.gcourseid ? this.gcourseid : item3.json.courses[0];
                   } else if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.json.answer2 !== 0 && item3.type == 7) {
                     item3.json.answer2 = '';
+                  } else if (item3.ttype == 1 && item3.json && !item3.json.answer2 && item3.json.answer2 !== 0 && item3.type == 8) {
+                    item3.json.answer2 = '';
                   }
                   return item3;
                 });
@@ -275,12 +289,14 @@ export default {
               );
             });
           }
-          if (item.ttype == 1 && item.json && !item.json.answer2 && item.type != 6 && item.type != 7) {
+          if (item.ttype == 1 && item.json && !item.json.answer2 && item.type != 6 && item.type != 7 && item.type != 8) {
             item.json.answer2 = [];
           } else if (item.ttype == 1 && item.json && !item.json.answer2 && item.type == 6) {
             item.json.answer2 = this.gcourseid ? this.gcourseid : item.json.courses[0];
           } else if (item.ttype == 1 && item.json && !item.json.answer2 && item.json.answer2 !== 0 && item.type == 7) {
             item.json.answer2 = '';
+          } else if (item.ttype == 1 && item.json && !item.json.answer2 && item.json.answer2 !== 0 && item.type == 8) {
+            item.json.answer2 = '';
           }
           console.log(item.array);
           return (item.ttype != 1 && item.array.length > 0) || item.ttype == 1;

+ 18 - 0
src/router/index.js

@@ -125,7 +125,9 @@ import studentEva from '@/components/pages/studentEva'
 import kindStudentEva from '@/components/pages/kindStudentEva/index'
 import record from '@/components/pages/record/class'
 import classroomObservation from '@/components/pages/classroomObservation/index'//课堂观察
+import contrastObservation from '@/components/pages/contrastObservation/index'//对比分析
 import pblCourse from '@/components/pages/pblCourse/index'
+import guide from '@/components/pages/pblCourse/guide'
 
 // 全局修改默认配置,点击空白处不能关闭弹窗
 ElementUI.Dialog.props.closeOnClickModal.default = false
@@ -1075,6 +1077,14 @@ export default new Router({
 						requireAuth:''//不需要鉴权
 					}
 				},
+				{//对比观察
+					path:"/contrastObservation",
+					name:"contrastObservation",
+					component:contrastObservation,
+					meta:{
+						requireAuth:''//不需要鉴权
+					}
+				},
 				{//pblCourse
 					path:"/pblCourse",
 					name:"pblCourse",
@@ -1082,6 +1092,14 @@ export default new Router({
 					meta:{
 						requireAuth:''//不需要鉴权
 					}
+				},
+                 {//pblCourse
+					path:"/guide",
+					name:"guide",
+					component:guide,
+					meta:{
+						requireAuth:''//不需要鉴权
+					}
 				}
     ]
 })

Some files were not shown because too many files changed in this diff