Преглед изворни кода

Merge branch 'beta' of https://git.cocorobo.cn/CocoRoboLabs/pbl-teacher-table into beta

lsc пре 4 месеци
родитељ
комит
8235ee405c
40 измењених фајлова са 2527 додато и 202 уклоњено
  1. 1 1
      dist/index.html
  2. 0 0
      dist/static/css/app.14aba7d36141b10cf095aa5442b4c6fe.css
  3. 0 0
      dist/static/css/app.14aba7d36141b10cf095aa5442b4c6fe.css.map
  4. 0 0
      dist/static/css/workPage.3639185b5b0b118d5c023498ff9db830.css
  5. 0 0
      dist/static/css/workPage.3639185b5b0b118d5c023498ff9db830.css.map
  6. 0 0
      dist/static/css/workPage.63dae65d2c64f60967d9c4d585b9d712.css.map
  7. 0 0
      dist/static/js/app.202dce7582036aaca568.js
  8. 0 0
      dist/static/js/app.202dce7582036aaca568.js.map
  9. 0 0
      dist/static/js/manifest.23ea04dc469b57e2b4f8.js.map
  10. 0 0
      dist/static/js/vendor.714ff2bfc93f2f096b79.js
  11. 0 0
      dist/static/js/vendor.714ff2bfc93f2f096b79.js.map
  12. 0 0
      dist/static/js/workPage-manifest.2ece51fa34be51c8610a.js.map
  13. 0 0
      dist/static/js/workPage-vendor.7b2c55096449c94cc8fd.js
  14. 0 0
      dist/static/js/workPage-vendor.7b2c55096449c94cc8fd.js.map
  15. 0 0
      dist/static/js/workPage-vendor.7e4b52d86fde7f24e41c.js
  16. 0 0
      dist/static/js/workPage-vendor.7e4b52d86fde7f24e41c.js.map
  17. 0 0
      dist/static/js/workPage.80cf0f8f0b3e00416d2a.js
  18. 0 0
      dist/static/js/workPage.80cf0f8f0b3e00416d2a.js.map
  19. 0 0
      dist/static/js/workPage.e8ba67d8caed072748d8.js
  20. 0 0
      dist/static/js/workPage.e8ba67d8caed072748d8.js.map
  21. 1 1
      dist/workPage.html
  22. 1 0
      src/assets/stuImg/ai6dui.svg
  23. 1 1
      src/components/pages/course.vue
  24. 16 8
      src/components/pages/pptEasy/addCourse2.vue
  25. 89 81
      src/components/pages/pptEasy/addCourse3.vue
  26. 228 0
      src/components/pages/pptEasy/commpont/aidia.vue
  27. 4 2
      src/components/pages/studentManageNew/component/addstu.vue
  28. 7 10
      src/components/pages/studentManageNew/component/editInterstcla.vue
  29. 73 15
      src/components/pages/studentManageNew/component/table.vue
  30. 372 18
      src/components/pages/studentManageNew/index.vue
  31. 13 1
      src/components/pages/workPage/components/questionsAndAnswers.vue
  32. 544 0
      src/components/pages/workPage/components/setChoiceQuestion.vue
  33. 465 0
      src/components/pages/workPage/components/setQuestionsAndAnswers.vue
  34. 110 0
      src/components/pages/workPage/setIndex.vue
  35. 519 0
      src/components/tools/uploadFile.js
  36. 15 31
      src/lang/cn.json
  37. 12 1
      src/lang/en.json
  38. 38 32
      src/lang/hk.json
  39. 9 0
      src/router/index.js
  40. 9 0
      src/router/index2.js

+ 1 - 1
dist/index.html

@@ -37,7 +37,7 @@
       width: 100%;
       background: #e6eaf0;
       font-family: '黑体';
-    }</style><link href=./static/css/app.24d92fd39ac8c531c796c35a0cc7ae42.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.23ea04dc469b57e2b4f8.js></script><script type=text/javascript src=./static/js/vendor.dfc8a8e3392292c7b8e5.js></script><script type=text/javascript src=./static/js/app.5947fbaedba1abc31f13.js></script></body></html><script>function stopSafari() {
+    }</style><link href=./static/css/app.14aba7d36141b10cf095aa5442b4c6fe.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.23ea04dc469b57e2b4f8.js></script><script type=text/javascript src=./static/js/vendor.714ff2bfc93f2f096b79.js></script><script type=text/javascript src=./static/js/app.202dce7582036aaca568.js></script></body></html><script>function stopSafari() {
     //阻止safari浏览器双击放大功能
     let lastTouchEnd = 0  //更新手指弹起的时间
     document.documentElement.addEventListener("touchstart", function (event) {

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/css/app.14aba7d36141b10cf095aa5442b4c6fe.css


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/css/app.14aba7d36141b10cf095aa5442b4c6fe.css.map


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/css/workPage.3639185b5b0b118d5c023498ff9db830.css


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/css/workPage.3639185b5b0b118d5c023498ff9db830.css.map


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/css/workPage.63dae65d2c64f60967d9c4d585b9d712.css.map


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/app.202dce7582036aaca568.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/app.202dce7582036aaca568.js.map


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/manifest.23ea04dc469b57e2b4f8.js.map


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/vendor.714ff2bfc93f2f096b79.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/vendor.714ff2bfc93f2f096b79.js.map


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/workPage-manifest.2ece51fa34be51c8610a.js.map


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/workPage-vendor.7b2c55096449c94cc8fd.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/workPage-vendor.7b2c55096449c94cc8fd.js.map


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/workPage-vendor.7e4b52d86fde7f24e41c.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/workPage-vendor.7e4b52d86fde7f24e41c.js.map


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/workPage.80cf0f8f0b3e00416d2a.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/workPage.80cf0f8f0b3e00416d2a.js.map


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/workPage.e8ba67d8caed072748d8.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/static/js/workPage.e8ba67d8caed072748d8.js.map


+ 1 - 1
dist/workPage.html

@@ -1,4 +1,4 @@
-<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>工作页面 - CocoFlow</title><link rel=icon href=../static/logo.ico><link href=./static/css/workPage.63dae65d2c64f60967d9c4d585b9d712.css rel=stylesheet></head><body><noscript><strong>We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script type=text/javascript src=./static/js/workPage-manifest.2ece51fa34be51c8610a.js></script><script type=text/javascript src=./static/js/workPage-vendor.7e4b52d86fde7f24e41c.js></script><script type=text/javascript src=./static/js/workPage.80cf0f8f0b3e00416d2a.js></script></body></html><script>function stopSafari() {
+<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>工作页面 - CocoFlow</title><link rel=icon href=../static/logo.ico><link href=./static/css/workPage.3639185b5b0b118d5c023498ff9db830.css rel=stylesheet></head><body><noscript><strong>We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script type=text/javascript src=./static/js/workPage-manifest.2ece51fa34be51c8610a.js></script><script type=text/javascript src=./static/js/workPage-vendor.7b2c55096449c94cc8fd.js></script><script type=text/javascript src=./static/js/workPage.e8ba67d8caed072748d8.js></script></body></html><script>function stopSafari() {
     //阻止safari浏览器双击放大功能
     let lastTouchEnd = 0  //更新手指弹起的时间
     document.documentElement.addEventListener("touchstart", function (event) {

+ 1 - 0
src/assets/stuImg/ai6dui.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774246495151" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4840" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M840.021333 267.690667a42.666667 42.666667 0 0 1 1.621334 60.330666l-384 405.333334a42.666667 42.666667 0 0 1-61.141334 0.853333l-213.333333-213.333333a42.666667 42.666667 0 1 1 60.330667-60.373334l182.357333 182.314667 353.834667-373.504a42.666667 42.666667 0 0 1 60.330666-1.621333z" p-id="4841" fill="#ffffff"></path></svg>

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

@@ -231,7 +231,7 @@
 								</div>
     					</el-tooltip>
 							<el-tooltip effect="dark" v-show="orgArray.includes(org) || oidArray.includes(oid)" :content="lang.AiEdit" placement="top">
-    					  <div class="t_b_Item" @click="aiCourse(item.courseId)">
+    					  <div v-if="lang.lang == 'cn'" class="t_b_Item" @click="aiCourse(item.courseId)">
 									<img src="../../assets/icon/course/aiEdit.svg">
 								</div>
     					</el-tooltip>

+ 16 - 8
src/components/pages/pptEasy/addCourse2.vue

@@ -15,14 +15,14 @@
                   </el-breadcrumb>
               </div>
               <div class="title">
-                <el-input 
-                  class="title-input" 
+                <el-input
+                  class="title-input"
                   ref="titleInputRef"
-                  v-model="titleValue" 
-                  @blur="handleUpdateTitle()" 
-                  v-if="editingTitle" 
+                  v-model="titleValue"
+                  @blur="handleUpdateTitle()"
+                  v-if="editingTitle"
                 ></el-input>
-                <div 
+                <div
                   class="title-text"
                   @click="startEditTitle()"
                   :title="courseName"
@@ -857,6 +857,7 @@
       width="500px"
       :before-close="handleClose"
       class="dialog_diy lineCss"
+      v-loading="isAddOrUpdateLineLoading"
     >
       <el-form>
         <el-form-item :label="lang.ssTitle" :label-width="formLabelWidth" v-show="false">
@@ -1112,7 +1113,7 @@ export default {
       choosePicVisible: false,
       searchImageValue: "",
       ppage: 1,
-      imageList: [],      
+      imageList: [],
       sysPicVisible2: false,
       isSysPic: false,
       isSysPic2: false,
@@ -1175,6 +1176,7 @@ export default {
       title: "",
       titleValue: "",
       editingTitle: false,
+      isAddOrUpdateLineLoading:false,
     };
   },
   directives: {
@@ -1301,7 +1303,7 @@ export default {
       ) {
         let _data = _pptIframe.contentWindow.window.setTitle(this.courseName);
         resolve(_data);
-      } 
+      }
     },
     closePan(tool) {
       if (tool == 15) {
@@ -2889,6 +2891,10 @@ export default {
         this.$message.error(this.lang.ssCocoLinkTip);
         return;
       }
+      if(this.isAddOrUpdateLineLoading){
+        return;
+      }
+      this.isAddOrUpdateLineLoading = true;
       //https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/%E6%97%A0%E6%B3%95%E5%93%87%E5%8F%91%E5%99%B6%E5%99%B6%E5%93%87_b634700f-f084-451d-8141-745d516f28c0.html
       // if(this.line.includes("ppt.cocorobo.cn")){
       //   this.$message.error("请使用ppt.cocorobo.cn的链接");
@@ -3042,6 +3048,7 @@ export default {
 
       if (!isValid) {
         this.$message.error(this.lang.ssCocoLinkTip);
+        this.isAddOrUpdateLineLoading = false
         return;
       }
 
@@ -3057,6 +3064,7 @@ export default {
       }
       this.setPPtToolList();
       this.dialogVisible7 = false;
+      this.isAddOrUpdateLineLoading = false;
 
     },
   },

+ 89 - 81
src/components/pages/pptEasy/addCourse3.vue

@@ -668,7 +668,7 @@
       </span>
     </el-dialog>
     <el-dialog :title="lang.ssAddH5" :visible.sync="dialogVisible7" :append-to-body="true" width="500px"
-      :before-close="handleClose" class="dialog_diy lineCss">
+      :before-close="handleClose" class="dialog_diy lineCss" v-loading="isAddOrUpdateLineLoading">
       <el-form>
         <el-form-item :label="lang.ssTitle" :label-width="formLabelWidth" v-show="false">
           <span>
@@ -683,7 +683,7 @@
       </el-form>
       <span slot="footer" class="dialog-footer">
         <el-button @click="clearLine">{{ lang.ssCancel }}</el-button>
-        <el-button type="primary" @click="isAddOrUpdateLine">{{ lang.ssConfirm }}</el-button>
+        <el-button type="primary" @click="isAddOrUpdateLine" >{{ lang.ssConfirm }}</el-button>
       </span>
     </el-dialog>
     <el-dialog :title="lang.ssAddQA" :visible.sync="dialogVisible8" :append-to-body="true" width="500px" :before-close="done => {
@@ -1144,6 +1144,7 @@ export default {
       subjectOptions: [],
       gradeOptions: [],
       avatar_loading: false,
+      isAddOrUpdateLineLoading: false,
     };
   },
   directives: {
@@ -1398,13 +1399,13 @@ export default {
 				{
 					role: "user",
 					content: `你是一名一流的UI设计师,现在你需要为这个场景设计相应的图标:
-									「${this.courseName}」 
+									「${this.courseName}」
 									请给出3个不同的设计方案。
-									## 要求 在你给出的设计方案中,坚持同时满足以下要求 
+									## 要求 在你给出的设计方案中,坚持同时满足以下要求
 									0. 要求体现学科特点 或者教学特点。
-									1. 背景底色为白色,正方形画面,画面填充满内容。 
-									2. 采用扁平化的设计风格 
-									3.不要在设计中设计到相关的文字,不如这个描述不允许类似这样的描述“繁体中文的“文”字,突出语言特色。”。 
+									1. 背景底色为白色,正方形画面,画面填充满内容。
+									2. 采用扁平化的设计风格
+									3.不要在设计中设计到相关的文字,不如这个描述不允许类似这样的描述“繁体中文的“文”字,突出语言特色。”。
 									## 输出一个json格式的回复,输出格式如下:
 									{"option":["方案一 核心视觉元素(2个):xxx 辅助视觉元素(1-3个):xxxx 核心情绪:xxx 主体颜色:xxx设计风格:xxxx 整体构图与画面内容:xxxx","方案二......","方案三......"]}`,
 				},
@@ -2472,11 +2473,13 @@ export default {
             }
           ]
         };
-        this.dialogVisibleChoice = true;
+         this.addTest()
+        // this.dialogVisibleChoice = true;
         // this.$message.info("添加选择题");
       } else if (tool == 15) {
         this.answerQ = "";
-        this.dialogVisible8 = true;
+        this.addAnswer();
+        // this.dialogVisible8 = true;
       } else if (tool == 72) {
         this.$refs.appDialog.openG(
           { url: "" },
@@ -2642,72 +2645,72 @@ export default {
       this.setPPtToolList();
     },
     addTest() {
-      var aj = this.testJson.testJson;
-      var b = 1;
-      for (var i = 0; i < aj.length; i++) {
-        if (aj[i].teststitle === "" && aj[i].timuList.length == 0) {
-          var a = 1;
-          for (let index = 0; index < aj[i].testItem; index++) {
-            const element = aj[i].checkList[index]
-              ? aj[i].checkList[index]
-              : "";
-            if (element != "") {
-              b++;
-              this.$message.error(this.lang.ssFillTitle.replace(/\*/g, i + 1));
-              return;
-            } else {
-              a++;
-            }
-          }
-          if (b == 1) {
-            this.$message.error(this.lang.ssOneQues);
-            return;
-          }
-        } else if (aj[i].teststitle != "" || aj[i].timuList.length > 0) {
-          for (let index = 0; index < aj[i].testItem; index++) {
-            const element = aj[i].checkList[index]
-              ? aj[i].checkList[index]
-              : "";
-            var index = 0;
-            for (var z = 0; z < aj[i].checkList.length; z++) {
-              var checkC = aj[i].checkList[z] ? aj[i].checkList[z] : "";
-              if (checkC != "") {
-                index++;
-              } else {
-                this.$message.error(this.lang.ssOptEmpty.replace(/\*/g, i + 1));
-                return;
-              }
-
-              for (var z2 = z + 1; z2 < aj[i].checkList.length; z2++) {
-                let checkC2 = aj[i].checkList[z2] ? aj[i].checkList[z2] : "";
-                if (checkC == checkC2) {
-                  this.$message.error(
-                    this.lang.ssOptDup
-                      .replace(/\*/g, i + 1)
-                      .replace("&", this.optionTypeList[z])
-                      .replace("$", this.optionTypeList[z2])
-                  );
-                  return;
-                }
-              }
-            }
-            b++;
-            if (index < 2) {
-              this.$message.error(this.lang.ssEachQues);
-              return;
-            }
-            if (
-              (aj[i].type == "2" && !aj[i].answer.length) ||
-              (aj[i].type == "1" &&
-                ((typeof aj[i].answer == "object" && !aj[i].answer.length) ||
-                  (aj[i].answer !== 0 && !aj[i].answer)))
-            ) {
-              this.$message.error(this.lang.ssCorrectOpt.replace(/\*/g, i + 1));
-              return;
-            }
-          }
-        }
-      }
+      // var aj = this.testJson.testJson;
+      // var b = 1;
+      // for (var i = 0; i < aj.length; i++) {
+      //   if (aj[i].teststitle === "" && aj[i].timuList.length == 0) {
+      //     var a = 1;
+      //     for (let index = 0; index < aj[i].testItem; index++) {
+      //       const element = aj[i].checkList[index]
+      //         ? aj[i].checkList[index]
+      //         : "";
+      //       if (element != "") {
+      //         b++;
+      //         this.$message.error(this.lang.ssFillTitle.replace(/\*/g, i + 1));
+      //         return;
+      //       } else {
+      //         a++;
+      //       }
+      //     }
+      //     if (b == 1) {
+      //       this.$message.error(this.lang.ssOneQues);
+      //       return;
+      //     }
+      //   } else if (aj[i].teststitle != "" || aj[i].timuList.length > 0) {
+      //     for (let index = 0; index < aj[i].testItem; index++) {
+      //       const element = aj[i].checkList[index]
+      //         ? aj[i].checkList[index]
+      //         : "";
+      //       var index = 0;
+      //       for (var z = 0; z < aj[i].checkList.length; z++) {
+      //         var checkC = aj[i].checkList[z] ? aj[i].checkList[z] : "";
+      //         if (checkC != "") {
+      //           index++;
+      //         } else {
+      //           this.$message.error(this.lang.ssOptEmpty.replace(/\*/g, i + 1));
+      //           return;
+      //         }
+
+      //         for (var z2 = z + 1; z2 < aj[i].checkList.length; z2++) {
+      //           let checkC2 = aj[i].checkList[z2] ? aj[i].checkList[z2] : "";
+      //           if (checkC == checkC2) {
+      //             this.$message.error(
+      //               this.lang.ssOptDup
+      //                 .replace(/\*/g, i + 1)
+      //                 .replace("&", this.optionTypeList[z])
+      //                 .replace("$", this.optionTypeList[z2])
+      //             );
+      //             return;
+      //           }
+      //         }
+      //       }
+      //       b++;
+      //       if (index < 2) {
+      //         this.$message.error(this.lang.ssEachQues);
+      //         return;
+      //       }
+      //       if (
+      //         (aj[i].type == "2" && !aj[i].answer.length) ||
+      //         (aj[i].type == "1" &&
+      //           ((typeof aj[i].answer == "object" && !aj[i].answer.length) ||
+      //             (aj[i].answer !== 0 && !aj[i].answer)))
+      //       ) {
+      //         this.$message.error(this.lang.ssCorrectOpt.replace(/\*/g, i + 1));
+      //         return;
+      //       }
+      //     }
+      //   }
+      // }
       let testJson = JSON.parse(JSON.stringify(this.testJson));
       testJson.testJson = this.testJson.testJson.filter(el => {
         var elc = el.checkList.filter(element => {
@@ -2733,7 +2736,7 @@ export default {
 
       this.dialogVisibleChoice = false;
       this.getWorkPageId(_data.id, 45, testJson).then(res => {
-        let url = `https://beta.pbl.cocorobo.cn/pbl-teacher-table/dist/workPage.html#/workPageNew?id=${res}`
+        let url = `https://beta.pbl.cocorobo.cn/pbl-teacher-table/dist/workPage.html#/setWorkPage?id=${res}&type=${_data.tool}`
         this.pptCourseJson.toolsList.find(i => i.id === _data.id).url = url;
         this.setPPtToolList();
         _data.url = url
@@ -2972,10 +2975,10 @@ export default {
       this.noneBtnImg = _tmp.length >= 1;
     },
     addAnswer() {
-      if (this.answerQ == "") {
-        this.$message.error(this.lang.ssEnterQuesL);
-        return;
-      }
+      // if (this.answerQ == "") {
+      //   this.$message.error(this.lang.ssEnterQuesL);
+      //   return;
+      // }
       let _data = { id: new Date().getTime(), tool: 15, title: this.lang.ssQAQuestion, brief: this.lang.ssQAQuestionTool, json: { answerQ: this.answerQ }, url: "" }
       if (this.editId) {
         let oldData = this.pptCourseJson.toolsList.find(i => i.id === this.editId);
@@ -2989,7 +2992,7 @@ export default {
 
       this.dialogVisible8 = false;
       this.getWorkPageId(_data.id, 15, { answerQ: this.answerQ }).then(res => {
-        let url = `https://beta.pbl.cocorobo.cn/pbl-teacher-table/dist/workPage.html#/workPageNew?id=${res}`;
+        let url = `https://beta.pbl.cocorobo.cn/pbl-teacher-table/dist/workPage.html#/setWorkPage?id=${res}&type=${_data.tool}`;
         this.pptCourseJson.toolsList.find(i => i.id === _data.id).url = url;
         this.setPPtToolList();
         _data.url = url
@@ -3067,6 +3070,9 @@ export default {
         this.$message.error(this.lang.ssCocoLinkTip);
         return;
       }
+
+      if(this.isAddOrUpdateLineLoading)return
+      this.isAddOrUpdateLineLoading = true
       //https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/%E6%97%A0%E6%B3%95%E5%93%87%E5%8F%91%E5%99%B6%E5%99%B6%E5%93%87_b634700f-f084-451d-8141-745d516f28c0.html
       // if(this.line.includes("ppt.cocorobo.cn")){
       //   this.$message.error("请使用ppt.cocorobo.cn的链接");
@@ -3220,6 +3226,7 @@ export default {
 
       if (!isValid) {
         this.$message.error(this.lang.ssCocoLinkTip);
+        this.isAddOrUpdateLineLoading = false
         return;
       }
 
@@ -3234,6 +3241,7 @@ export default {
         this.addContent(_data)
       }
       this.setPPtToolList();
+      this.isAddOrUpdateLineLoading = false
       this.dialogVisible7 = false;
 
     },

+ 228 - 0
src/components/pages/pptEasy/commpont/aidia.vue

@@ -0,0 +1,228 @@
+<template>
+    <div class="ai_dialog">
+        <el-dialog
+            :visible.sync="dialogVisibleAiD"
+            width="700px"
+            :show-close="false"
+            :before-close="handleClose">
+            <template #title>
+                <div class="title_container">
+                    <div>{{ lang.ssCourseCenter }}</div>
+                    <div class="close_btn" @click="handleClose">×</div>
+                </div>
+            </template>
+            <div class="course_type_container">
+                <div class="course_type_title">
+                    {{ lang.ssCourseType }}
+                </div>
+                <div class="course_type_select">
+                    <el-select v-model="courseType" :placeholder="lang.ssSelectCourseType" @change="typeChange">
+                        <el-option 
+                            v-for="item in courseTypeList" 
+                            :key="item.id" 
+                            :label="item.name" 
+                            :value="item.id">
+                            <span>{{ item.name }}</span>
+                        </el-option>
+                    </el-select>
+                </div>
+            </div>
+            <div class="course_type_list">
+                    <div v-for="item in courseList" @click="selectCourse(item)" :key="item.id" class="course_item" :class="{'selected': selectedCourseList.includes(item)}">
+                        <img class="course_item_selected" 
+                            src="../../../../assets/stuImg/ai6dui.svg" 
+                            v-if="selectedCourseList.includes(item)"
+                        alt="">
+                        <img class="course_item_img" :src="item.img" alt="">
+                        <div class="course_item_name">
+                            {{ item.name }}
+                        </div>
+                    </div>
+            </div>
+            <div class="course_item_footer">
+                <div>{{ lang.ssSelectedCourse.replace(/\*/g, selectedCourseList.length) }}</div>
+                <div class="confirm_btn" @click="confirmAddCourse">
+                    <img src="../../../../assets/stuImg/ai6dui.svg" alt="">
+                    {{ lang.ssConfirm }}
+                </div>
+            </div>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'aiDialog',
+    data() {
+        return {
+            dialogVisibleAiD: true,
+            courseType: '',
+            courseTypeList: [],
+            courseList: [],
+            allCourseList: [],
+            selectedCourseList: []
+        }
+    },
+    methods: {
+        openDialog() {
+            this.dialogVisibleAiD = true;
+        },
+        handleClose() {
+            this.dialogVisibleAiD = false;
+        },
+        selectCourse(item) {
+            if(this.selectedCourseList.includes(item)) {
+                this.selectedCourseList = this.selectedCourseList.filter(item => item.id !== item.id);
+            } else {
+                this.selectedCourseList.push(item);
+            }
+        },
+        confirmAddCourse() {
+            let courseIds = this.selectedCourseList.map(item => item.id);
+            console.log(courseIds);
+        },
+        getCourseTypeList() {
+            let params = {
+                cl: 1,
+            };
+            this.ajax.get(this.$store.state.api + 'selectAiExp', params).then(res => {
+                let data = res.data
+                this.courseTypeList = data[0];
+                this.courseTypeList.unshift({id: '', name: this.lang.ssAll});
+                this.courseList = data[1];
+                this.allCourseList = data[1];
+            })
+            .catch(err => {
+                console.error(err);
+            });
+        },
+        typeChange(value) {
+            console.log(value);
+            if(value === '') {
+                this.courseList = this.allCourseList;
+            } else {
+                this.courseList = this.allCourseList.filter(item => item.levA === value);
+            }
+        }
+    },
+    mounted() {
+        this.getCourseTypeList();
+    }
+}
+</script>
+<style scoped>
+.ai_dialog >>> .el-dialog {
+    border-radius: 10px;
+}
+.title_container {
+    display: flex;
+    font-size: 16px;
+    font-weight: bold;
+    justify-content: space-between;
+    align-items: center;
+}
+.close_btn {
+    cursor: pointer;
+    background-color: #F5F6F6;
+    padding: 3px 7px;
+    border-radius: 5px;
+}
+.course_type_container {
+    display: flex;
+    flex-direction: column;
+    gap: 10px;
+    border-bottom: 1px solid #E5E5E5;
+    padding-bottom: 10px;
+}
+.course_type_title {
+    font-size: 14px;
+}
+.course_type_select >>> .el-select {
+    width: 33%;
+    border-radius: 10px;
+    background-color: #F5F6F6;
+}
+.course_type_select >>> .el-select .el-input__inner {
+    background-color: #FAFCFE;
+    border-radius: 10px;
+}
+.ai_dialog >>> .el-dialog__body {
+    padding: 10px 20px;
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+}
+.course_type_list {
+    display: grid;
+    grid-template-columns: repeat(3, 1fr);
+    max-height: 400px;
+    height: 350px;
+    overflow-y: auto;
+    gap: 15px;
+}
+.course_item {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    gap: 10px;
+    height: 160px;
+    padding: 15px;
+    box-sizing: border-box;
+    border-radius: 10px;
+    position: relative;
+    border: 1px solid #E5E5E5;
+    cursor: pointer;
+}
+.course_item.selected {
+    border: 2px solid #FF9400;
+}
+.course_item_selected {
+    position: absolute;
+    top: 10px;
+    right: 10px;
+    width: 20px;
+    height: 20px;
+    padding: 2px;
+    box-sizing: border-box;
+    border-radius: 50%;
+    background-color: #FF9400;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: #fff;
+    font-size: 12px;
+    font-weight: bold;
+    z-index: 1;
+}
+.course_item_img {
+    width: 100%;
+    border-radius: 5px;
+    object-fit: contain;
+}
+.course_item_footer {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 10px;
+    box-sizing: border-box;
+    border-top: 1px solid #E5E5E5;
+}
+.confirm_btn {
+    background-color: #FF9400;
+    color: #fff;
+    font-size: 14px;
+    border-radius: 10px;
+    display: flex;
+    padding: 7px 10px;
+    align-items: center;
+    justify-content: center;
+    /* padding: 5px 10px; */
+    border: none;
+    cursor: pointer;
+}
+.confirm_btn img {
+    width: 22px;
+    height: 22px;
+    margin-right: 5px;
+}
+</style>

+ 4 - 2
src/components/pages/studentManageNew/component/addstu.vue

@@ -250,7 +250,6 @@ export default {
         if (newVal == 1) {
           this.stuListTypeList = [];
           this.addStuType = 3;
-          // this.$refs.allClaAddSturef.clearData();
         } else if (newVal == 0) {
           this.stuListTypeList = this.tab1;
           this.addStuType = 1;
@@ -346,9 +345,12 @@ export default {
 
       // this.addStuType=1
       if (this.boxType == 1) {
-        this.$refs.allClaAddSturef.clearData();
         this.stuListTypeList = [];
         this.addStuType = 3;
+        // this.nextTick(() => {
+        //   this.$refs.allClaAddSturef.clearData();
+        // });
+
       } else if (this.boxType == 0) {
         this.stuListTypeList = this.tab1;
         this.addStuType = 1;

+ 7 - 10
src/components/pages/studentManageNew/component/editInterstcla.vue

@@ -35,11 +35,7 @@ export default {
     interestClaEditInfo: {
       type: Object,
       default: () => {},
-    },
-    cascaderData: {
-      type: Array,
-      default: () => [],
-    },
+    }
   },
   watch: {
     interestClaEditInfo: {
@@ -56,11 +52,6 @@ export default {
       oid: this.$route.query.oid,
       role: this.$route.query.role,
       clainfo: {}, // 班级信息
-      studentColumns: [
-        { label: this.lang.StudentName, prop: "username" },
-        { label: this.lang.Account, prop: "acc" },
-        { label: this.lang.Class, prop: "classname" },
-      ],
       InterestClaEditvisible: false, // 兴趣班编辑信息
       isLoading: false, // 是否加载中
     };
@@ -102,6 +93,10 @@ export default {
               message: this.lang.Editsuccessful,
               type: "success",
             });
+            // this.$emit("getInterestClass"); 
+            this.$emit("getCascaderData");
+            this.InterestClaEditvisible = false;
+
             this.addOp3('1', "", { type: "interest_class_edit" }, "success")
           }
         })
@@ -110,6 +105,8 @@ export default {
             message: this.lang.Modificationfailed,
             type: "error",
           });
+          this.InterestClaEditvisible = false;
+
           console.error(err);
           this.addOp3('1', "", { type: "interest_class_edit" }, err)
         });

+ 73 - 15
src/components/pages/studentManageNew/component/table.vue

@@ -183,7 +183,7 @@
         </div>
       </div>
     </div>
-    <div class="tabList" v-loading="isLoading">
+    <div class="tabList" v-loading="boxType == 0 ? tab0Loading : boxType == 1 ? tab1Loading : boxType == 2 ? tab2Loading : false">
       <el-table
         :data="tableDataList"
         ref="tableData"
@@ -277,7 +277,7 @@
                     <div @click="editStudent(scope.row)">{{ lang.edit }}</div>
                     <div
                       v-if="boxType == 1 && interestType == 1"
-                      @click="deleteClassStudent(scope.row.userid)"
+                      @click="deleteClassStudentone(scope.row)"
                     >
                       {{ lang.Remove }}
                     </div>
@@ -536,6 +536,7 @@
     <editInterstcla
       ref="editInterstcla"
       @getCascaderData="getCascaderData"
+      @getInterestClass="getInterestClass"
       :cascaderData="cascaderData"
       :interestClaEditInfo="InterestClaEditInfo"
     />
@@ -589,6 +590,9 @@
             <div v-if="deltypy == 10">
               {{ lang.ssConfirmEditStu.replace(/\*/g, stuEditInfo.username) }}
             </div>
+            <div v-if="deltypy == 11">
+              {{ lang.ssConfirmDeleteClassStudentone.replace(/\*/g, deleteClassStudentoneId.username) }}
+            </div>
           </div>
           <div class="msgContxt" v-if="deltypy == 7 || deltypy == 8">
             <div v-if="deltypy == 7">
@@ -687,6 +691,12 @@ export default {
       popBoxdia: false,
       insort: 0,
       EditStubox: "",
+      tab0Loading: false,
+      tab1Loading: false,
+      tab2Loading: false,
+
+      deleteClassStudentoneId: {}, // 兴趣班移除学生信息
+
 
       delClaid: "",
       delClaidtype: "",
@@ -790,7 +800,7 @@ export default {
     },
     stuClalist() {
       return function(data, val) {
-        // console.log(data, "data");
+        // console.log(data, "data"); 
         if (data.length == 0) {
           return [];
         }
@@ -1083,6 +1093,36 @@ export default {
           });
       });
     },
+    deleteClassStudentone(val) {
+      this.deltypy = 11;
+      this.popBoxdia = true;
+      this.deleteClassStudentoneId = val;
+    },
+    confirmDeleteClassStudentone() {
+      this.popBoxdia = false;
+      let params = [{ uid: this.deleteClassStudentoneId.userid, cid: this.activeId }];
+        this.ajax
+          .post(this.$store.state.api + "deleteClassStudent", params)
+          .then(res => {
+            console.log("res", res);
+            this.$message({
+              message: this.lang.ssRemoveStuSucc,
+              type: "success"
+            });
+            this.popBoxdia = false;
+            this.deleteClassStudentoneId = {};
+            this.refresh();
+            this.$emit("getGrade");
+          })
+          .catch(err => {
+            this.$message({
+              message: this.lang.ssRemoveStuFail,
+              type: "error"
+            });
+            this.deleteClassStudentoneId = {};
+            console.error(err);
+          });
+    },
 
     // 批量重置密码
     resetPassword() {
@@ -1228,6 +1268,9 @@ export default {
       } else if (this.deltypy == 10) {
         this.update_Student(this.EditStubox);
         this.addOp3('1', "", { type: "student_edit" }, "success")
+      } else if (this.deltypy == 11) {
+        this.confirmDeleteClassStudentone();
+        this.addOp3('1', "", { type: "student_remove" }, "success")
       }
     },
     // 删除学生
@@ -1468,13 +1511,14 @@ export default {
           });
           this.stuEditvisible = false;
           this.refresh();
+          this.$emit("getGrade");
           this.popBoxdia = false;
           this.EditStubox = "";
           this.stuEditInfo = {};
           this.cascaderDataPath = [];
         })
         .catch(err => {
-          this.isLoading = false;
+          // this.isLoading = false;
           this.$message({
             message: this.lang.Modificationfailed,
             type: "error"
@@ -1593,7 +1637,11 @@ export default {
       }
     },
     getStudent() {
-      this.isLoading = true;
+      if(this.boxType == 0){
+        this.tab0Loading = true;
+      }else if(this.boxType == 1){
+        this.tab1Loading = true;
+      }
       this.tableColumns = [];
       this.tableColumns = this.studentColumns;
       let params = {
@@ -1604,7 +1652,11 @@ export default {
       this.ajax
         .get(this.$store.state.api + "selectclaStu", params)
         .then(res => {
-          this.isLoading = false;
+          if(this.boxType == 0){
+            this.tab0Loading = false;
+          }else if(this.boxType == 1){
+            this.tab1Loading = false;
+          }
           let box1 = res.data[0];
           box1.forEach(e => {
             let kk = [];
@@ -1625,13 +1677,17 @@ export default {
           );
         })
         .catch(err => {
-          this.isLoading = false;
+          if(this.boxType == 0){
+            this.tab0Loading = false;
+          }else if(this.boxType == 1){
+            this.tab1Loading = false;
+          }
           console.error(err);
         });
     },
     // 获取兴趣班
     getInterestClass() {
-      this.isLoading = true;
+      this.tab1Loading = true;
       this.tableColumns = this.tableInterestClaColumns;
       let params = {
         oid: this.oid,
@@ -1645,18 +1701,18 @@ export default {
       this.ajax
         .get(this.$store.state.api + "selectInterestcla", params)
         .then(res => {
-          this.isLoading = false;
+          this.tab1Loading = false;
           this.total = res.data[0].length > 0 ? res.data[0][0].num : 0;
           this.interestTableData = res.data[0];
         })
         .catch(err => {
-          this.isLoading = false;
+          this.tab1Loading = false;
           console.error(err);
         });
     },
     // 学生管理全部学生
     getAllStudent() {
-      this.isLoading = true;
+      this.tab2Loading = true;
       this.cancelAllSelection();
       this.tableColumns = this.studentColumns;
       let params = {
@@ -1670,7 +1726,7 @@ export default {
       this.ajax
         .get(this.$store.state.api + "selectStudentManagesrt", params)
         .then(res => {
-          this.isLoading = false;
+          this.tab2Loading = false;
           this.total = res.data[0].length > 0 ? res.data[0][0].num : 0;
           let box1 = res.data[0];
           box1.forEach(e => {
@@ -1688,7 +1744,7 @@ export default {
           this.allTableData = res.data[0];
         })
         .catch(err => {
-          this.isLoading = false;
+          this.tab2Loading = false;
           console.error(err);
         });
     },
@@ -1940,13 +1996,15 @@ export default {
   flex-wrap: wrap;
   align-items: center;
   gap: 10px;
-  height: 30px;
-  line-height: 30px;
+  /* height: 30px; */
+  /* line-height: 30px; */
 }
 .cla_span {
   background: #e8f3ff;
   color: #0052d9;
   padding: 0px 25px;
+  height: 30px;
+  line-height: 30px;
   border-radius: 5px;
   box-sizing: border-box;
 }

+ 372 - 18
src/components/pages/studentManageNew/index.vue

@@ -5,32 +5,56 @@
         <img src="../../../assets/stuImg/riqi.svg" alt="" />
         <span style="color: #86909c; font-size: 12px">{{ lang.GradeManagement }}</span>
       </div>
-      <!-- v-if="orglist.includes(org)" -->
-
-      <!-- <div > -->
       <div style="display: flex; gap: 10px;">
-        <div v-if="orglist.includes(org) || this.role == 1" class="Clabtn" @click="openaddClass(1)">
+        <div v-if="this.role == 1" class="Clabtn" @click="openaddClass(1)">
           <img src="../../../assets/stuImg/jia.svg" alt="" />
-          <span>{{ lang.ssNewGrade }}</span>
+          <span>{{ lang.ssGradeType }}</span>
         </div>
         <div class="Clabtn" @click="openaddClass(0)">
           <img src="../../../assets/stuImg/jia.svg" alt="" />
-          <span>{{ lang.ssNewClass }}</span>
+          <span>{{ lang.ssClass }}</span>
         </div>
       </div>
-        
+      <!-- <div v-if="this.role == 1" class="gradebtn" @click="editGrade">
+        <img src="../../../assets/stuImg/eidl.svg" style="width: 20px;" alt="" />
+        <span>{{ lang.ssEditGrade }}</span>
+      </div> -->
+      <div @mouseleave="mouseLeave()">
         <el-menu
           :default-active="activeId"
           class="el-menu-vertical-demo"
         >
           <el-submenu v-for="item in tableData" :index="item.id" :key="item.id">
             <template slot="title">
-              <div class="tabcla_box">{{ item.name }}</div>
-              <img
-                class="grade-submenu-arrow"
-                src="../../../assets/stuImg/zankai.svg"
-                alt=""
-              />
+              <div class="grade_submenu_title" @mouseenter="mouseEnter(item.id)">
+                <div class="tabcla_box">{{ item.name }}</div>
+                <img
+                  class="grade-submenu-arrow"
+                  src="../../../assets/stuImg/zankai.svg"
+                  alt=""
+                />
+                <div v-if="role == 1 && (mouseEnterId == item.id || mouseEnterId2 == item.id)">
+                  <el-popover
+                      placement="bottom-end"
+                      width="80"
+                      :visible-arrow="false"
+                      trigger="hover"
+                      popper-class="student-manage-action-popover"
+                      >
+                      <div 
+                        class="action_box" @mouseenter="mouseEnter2(item.id)">
+                          <div @click="editGrade(item)">编辑</div>
+                          <div @click="deleteGradeItem(item.id)">删除</div>
+                      </div>
+                        <div
+                          slot="reference"
+                          class="grade_submenu_arrow_box"
+                        >
+                          <img src="../../../assets/stuImg/act.svg" alt="">
+                        </div>
+                  </el-popover>
+                </div>
+                </div>
             </template>
             <el-menu-item-group
               v-for="k in item.children"
@@ -44,8 +68,7 @@
             </el-menu-item-group>
           </el-submenu>
         </el-menu>
-      <!-- </div> -->
-
+      </div>
       <div class="line"></div>
       <div class="centerCss">
         <img src="../../../assets/stuImg/inf.svg" alt="" />
@@ -118,6 +141,7 @@
       </div>
     </el-dialog>
 
+    <!-- 新增年级弹框 -->
     <el-dialog
       :title="lang.AddGrade"
       :visible.sync="addgraVisible"
@@ -136,6 +160,83 @@
         <div @click="addgra" style="background: #3681FC; color: #E6FFFFFF;">{{ lang.Confirm }}</div>
       </div>
     </el-dialog>
+
+    <!-- 编辑年级弹框 -->
+    <!-- <el-dialog
+      :title="lang.ssEditGrade"
+      :visible.sync="editGradeVisible"
+      width="500px"
+      :show-close="false"
+      class="addClassDialog2"
+    >
+      <div class="edit_grade_box" v-loading="editGradeLoading">
+        <div v-for="item in editGradeData" :key="item.id" class="edit_grade_box_item">
+          <div class="edit_grade_box_item_input">
+            <el-input @keyup.enter.native="confirmEditGrade(item.id)" v-if="item.id == editGradeId" v-model.trim="editGradeName" :placeholder="lang.EnterGrade"></el-input>
+            <div v-else>{{ item.name }}</div>
+          </div>
+          <div style="display: flex; align-items: center; gap: 15px;">
+            <span style="cursor: pointer;" v-if="item.id == editGradeId" @click="confirmEditGrade(item.id)">确定</span>
+            <span v-else style="cursor: pointer;" @click="editGradeItem(item)">编辑</span>
+            <span style="cursor: pointer;" @click="deleteGradeItem(item.id)">删除</span>
+          </div>
+        </div>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <div @click="closeEditGrade" style="color: #363636;">{{ lang.Close }}</div>
+      </div>
+    </el-dialog> -->
+
+    <div class="pop-upBox">
+      <el-dialog :visible.sync="popBoxdia" width="480px" :show-close="false">
+        <div class="msgCon">
+          <img
+            style="width: 20px;"
+            src="../../../assets/stuImg/tishi.svg"
+            alt=""
+          />
+          <div class="msgContxt">
+            <div>
+              {{ lang.Aystdtg }}
+            </div>
+          </div>
+       
+        </div>
+        <span slot="footer" class="dialog-footer">
+        
+          <div @click="popBoxdia = false">
+            {{ lang.Cancel }}
+          </div>
+          <div
+            @click="confirmDeleteGrade"
+            style="background: #3681FC; color: #E3EDFF;"
+          >
+            {{ lang.Confirm }}
+          </div>
+        </span>
+      </el-dialog>
+    </div>
+
+
+    <el-dialog
+      :title="lang.ssEditGrade"
+      :visible.sync="editGradeVisible"
+      width="500px"
+      :show-close="false"
+      class="addClassDialog"
+    >
+      <div class="addcla_box">
+        <div class="addcla_box_item">
+          <span>{{ lang.ssGradeType }}:</span>
+          <el-input v-model.trim="editGradeName" :placeholder="lang.EnterGrade"></el-input>
+        </div>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <div @click="editGradeVisible = false" style="color: #363636;">{{ lang.Cancel }}</div>
+        <div @click="confirmEditGrade" style="background: #3681FC; color: #E6FFFFFF;">{{ lang.Confirm }}</div>
+      </div>
+    </el-dialog>
+
   </div>
 </template>
 
@@ -154,6 +255,10 @@ export default {
       oid: this.$route.query.oid,
       role: this.$route.query.role,
 
+      mouseEnterId:'',
+      mouseEnterId2:'',
+
+      editGradeVisible:false,
       boxLoading: false, //年级区域loading
       addClassVisible: false,
       addgraVisible:false,
@@ -166,7 +271,12 @@ export default {
         "1973f6c7-1561-11ee-91d8-005056b86db5",
         "16ace517-b5c7-4168-a9bb-a9e0035df840"
       ],
-
+      popBoxdia:false,
+      editGradeId:'',
+      deleteGradeId:'',
+      editGradeLoading:false,
+      editGradeName:'',
+      editGradeData:[],
 
       tableData: [], //年级列表
       cascaderData: [], //年级列表加兴趣班列表
@@ -178,6 +288,106 @@ export default {
     };
   },
   methods: {
+    mouseEnter(id){
+      this.mouseEnterId = id;
+      this.mouseEnterId2 = id;
+    },
+    mouseLeave(){
+        this.mouseEnterId = '';
+        setTimeout(() => {
+          if (this.mouseEnterId == '') {
+            this.mouseEnterId2 = '';
+          }
+        }, 500);
+    },
+    mouseEnter2(id){
+      this.mouseEnterId = id;
+      this.mouseEnterId2 = id;
+    },
+
+    // 编辑年级
+    editGrade(val){
+      console.log('editGrade');
+      this.editGradeId = val.id;
+      this.editGradeName = val.name;
+      this.editGradeVisible = true;
+    },
+
+    // 确认编辑年级
+    confirmEditGrade(){
+      if (!this.editGradeName) {
+        this.$message.error(this.lang.EnterGradeName)
+        this.editGradeName = this.tableData.find((item) => item.id == this.editGradeId).name
+        return;
+      }
+      // if (this.editGradeName == this.tableData.find((item) => item.id == this.editGradeId).name) {
+      //   console.log('111');
+      //   return;
+      // }
+      let params = {
+        id: this.editGradeId,
+        n: this.editGradeName,
+        oid: this.oid,
+      };
+      this.ajax
+        .get(this.$store.state.api + "updateGrade", params)
+        .then((res) => {
+          if (res.data[0] && res.data[0][0].classname == 1) {
+            this.$message({
+              message: this.lang.Cannotsameother,
+              type: "error",
+            });
+          } else {
+            this.$message({
+              message: this.lang.Editsuccessful,
+              type: "success",
+            });
+            this.addOp3('1', "", { type: "grade_edit" }, "success")
+            this.editGradeId = '';
+            this.editGradeName = '';
+            this.editGradeVisible = false;
+            this.getGrade();
+          }
+        })
+        .catch((err) => {
+          this.$message({
+            message: this.lang.Modificationfailed,
+            type: "error",
+          });
+          console.error(err);
+          this.addOp3('1', "", { type: "grade_edit" }, err)
+        });
+    },
+
+    // 删除年级
+    deleteGradeItem(id){
+      this.popBoxdia = true;
+      this.deleteGradeId = id;
+    },
+    // 确认删除年级
+    confirmDeleteGrade(){
+      let params = {
+        id: this.deleteGradeId,
+      };
+      
+      this.ajax
+        .get(this.$store.state.api + "deleteGrade", params)
+        .then((res) => {
+          this.$message({
+            message: this.lang.Successfullydelete,
+            type: "success",
+          });
+          this.popBoxdia = false;
+          this.deleteGradeId = '';
+          this.getGrade();
+          this.addOp3('1', "", { type: "grade_delete" }, "success")
+        })
+        .catch((err) => {
+          this.$message.error(this.lang.Deletefailed);
+          this.addOp3('1', "", { type: "grade_delete" }, err)
+          console.error(err);
+        });
+    },
     // 添加年级
     addgra(){
       if (!this.addgraName) {
@@ -340,6 +550,36 @@ export default {
         this.$refs.tableLref.refresh();
       }
     },
+    // closeEditGrade(){
+    //   this.editGradeVisible = false;
+    //   this.editGradeId = '';
+    //   this.editGradeName = '';
+    //   this.editGradeData = [];
+    // },
+    // 编辑年级
+    // editGradeItem(val){
+    //   this.editGradeId = val.id;
+    //   this.editGradeName = val.name;
+    // },
+    // 获取编辑年级数据
+    // getEditGradeData(){
+    //   this.editGradeLoading = true;
+    //   let params = {
+    //     cu:'',
+    //     oid: this.oid,
+    //   };
+    //   this.ajax
+    //     .get(this.$store.state.api + "selectGradenewyym", params)
+    //     .then((res) => {
+    //       this.editGradeData = res.data[0];
+    //       this.editGradeLoading = false;
+    //     })
+    //     .catch((err) => {
+    //       this.editGradeData = [];
+    //       this.editGradeLoading = false;
+    //       console.error(err);
+    //     });
+    // },
   },
   mounted() {
     this.boxLoading = true;
@@ -347,7 +587,44 @@ export default {
   },
 };
 </script>
+<style>
+
+/* 学生管理表格操作弹窗样式 - 全局样式(Element UI popover 挂载到 body,需要全局样式) */
+.student-manage-action-popover {
+  width: 80px !important;
+  min-width: 60px !important;
+  padding: 0 !important;
+  margin-top: -3px !important;
+  border: none !important;
+}
 
+.grade_submenu_arrow_box{
+  display: flex;
+  align-items: center;
+}
+.grade_submenu_title{
+  width: 100%;
+  height: 35px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.student-manage-action-popover .action_box > div {
+  padding: 8px 15px;
+  cursor: pointer;
+  font-size: 14px;
+  text-align: center;
+}
+.student-manage-action-popover .action_box > div:hover {
+  background: #e8f3ff;
+  color: #0052d9;
+}
+.topbox_area_popover {
+  width: 152px !important;
+  min-width: 60px !important;
+  padding: 0 !important;
+}
+</style>
 <style scoped>
 .box {
   padding: 15px;
@@ -474,6 +751,13 @@ export default {
   flex-direction: column;
   gap: 10px;
 }
+.edit_grade_box {
+  display: flex;
+  flex-direction: column;
+  overflow: auto;
+
+  gap: 10px;
+}
 .addcla_box_item {
   display: flex;
   align-items: center;
@@ -489,10 +773,22 @@ export default {
 }
 .addClassDialog >>> .el-dialog {
   border-radius: 10px !important;
-  height: 427px !important;
+  height: 500px !important;
   display: flex;
   flex-direction: column;
 }
+.addClassDialog2 >>> .el-dialog {
+  border-radius: 10px !important;
+  height: auto !important;
+  display: flex;
+  flex-direction: column;
+}
+.addClassDialog2 >>> .el-dialog__body {
+  max-height: 400px;
+  height: 300px;
+  overflow: auto;
+  padding-top: 10px;
+}
 .addClassDialog >>> .el-dialog__body {
   flex: 1;
 }
@@ -510,5 +806,63 @@ export default {
   box-sizing: border-box;
   font-size: 14px;
 }
-
+.gradebtn{
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 3px;
+  color: #0052d9;
+  background: #e8f3ff;
+  border-radius: 3px;
+  padding: 5px 4px;
+  box-sizing: border-box;
+  height: 30px;
+  font-size: 14px;
+  cursor: pointer;
+}
+.edit_grade_box_item{
+  display: flex;
+  align-items: center;
+  height: 35px;
+  justify-content: space-between;
+  gap: 10px;
+}
+.edit_grade_box_item_input{
+  flex: 1;
+  font-size: 14px;
+  color: #000000;
+}
+.edit_grade_box_item_input >>> .el-input{
+  width: 100%;
+}
+.edit_grade_box_item_input >>> .el-input__inner{
+  width: 100%;
+  height: 30px;
+  border: none;
+  padding: 0;
+  color: #000000;
+  font-size: 14px;
+  border-radius: 0;
+  border-bottom: 1px solid #ccc;
+}
+.pop-upBox >>> .el-dialog {
+  border-radius: 8px !important;
+  margin-top: 30vh !important;
+}
+.pop-upBox >>> .el-dialog__body {
+  padding: 12px 23px;
+}
+.msgCon {
+  display: flex;
+  gap: 10px;
+  align-items: flex-start;
+  box-sizing: border-box;
+}
+.msgContxt {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  font-size: 16px;
+  color: #000000;
+}
 </style>

+ 13 - 1
src/components/pages/workPage/components/questionsAndAnswers.vue

@@ -155,7 +155,19 @@ export default {
       iframe.contentWindow.ConversationTranscriber();
       this.recordObj.status = "1"
       this.recordObj.startTime = new Date().getTime();
-
+      setTimeout(()=>{
+        navigator.permissions && navigator.permissions.query({ name: 'microphone' }).then(permissionStatus => {
+        if (permissionStatus.state !== "granted") {
+          // 没有开启录音权限,直接确定停止录音
+          this.recordObj.status = "0";
+          this.recordObj.loading = false;
+          iframe.contentWindow.onSessionStopped = null;
+          iframe.contentWindow.window.onRecognizedResult = null;
+          this.$message.success(this.lang.ssNoPermStop);
+          return;
+        }
+      })
+      },2000)
     },
     stopRecord() {
       console.log("测试测试")

+ 544 - 0
src/components/pages/workPage/components/setChoiceQuestion.vue

@@ -0,0 +1,544 @@
+<template>
+  <div class="setChoiceQuestion">
+    <div class="testItem" v-for="(item, index) in jsonData.testJson" :key="item.id">
+      <div class="ti_header">
+        <span>{{ lang.ssTopic }}{{ index + 1 }}</span>
+        <div class="ti_h_edit">
+          <span @click="copyTest(item.id)">
+            <svg viewBox="0 0 1024 1024" version="1.1" p-id="4608" width="200" height="200">
+              <path
+                d="M731.68184 676.057473 731.68184 183.323259c0-30.233582-24.512277-54.745858-54.747905-54.745858L184.216093 128.577401c-30.233582 0-54.746882 24.512277-54.746882 54.745858l0 492.734214c0 30.207999 24.5133 54.746882 54.746882 54.746882l492.717841 0C707.16854 730.804355 731.68184 706.265472 731.68184 676.057473zM622.1891 676.057473 238.962975 676.057473c-30.233582 0-54.746882-24.538883-54.746882-54.745858L184.216093 238.07014c0-30.233582 24.5133-54.746882 54.746882-54.746882l383.226125 0c30.233582 0 54.744835 24.512277 54.744835 54.746882l0 383.242498C676.933935 651.51859 652.421658 676.057473 622.1891 676.057473zM841.17458 292.817022l-54.745858 0 0 54.746882c30.232558 0 54.745858 24.5133 54.745858 54.759161l0 383.228171c0 30.206976-24.5133 54.745858-54.745858 54.745858L403.201573 840.297095c-30.233582 0-54.746882-24.538883-54.746882-54.745858l-54.746882 0 0 54.745858c0 30.207999 24.5133 54.747905 54.746882 54.747905l492.719888 0c30.234605 0 54.747905-24.539906 54.747905-54.747905L895.922485 347.563904C895.922485 317.329299 871.408161 292.817022 841.17458 292.817022z"
+                p-id="4609"></path>
+            </svg>
+          </span>
+          <span @click="deleteTest(item.id)">
+            <svg viewBox="0 0 1024 1024" version="1.1" p-id="12415" width="200" height="200">
+              <path
+                d="M902.4 282.1H117.7c-13.4 0-23.5-10.1-23.5-23.5v-3.4c0-13.4 10.1-23.5 23.5-23.5h788.1c13.4 0 23.5 10.1 23.5 23.5v3.4c0 13.4-10.1 23.5-26.9 23.5zM634.1 151.3H386c-13.4 0-26.8-10.1-23.5-23.5v-6.7c0-13.4 10.1-23.5 23.5-23.5h248.2c13.4 0 23.5 10.1 23.5 23.5v3.4c3.3 13.3-10.1 26.8-23.6 26.8z m228.1 238.1c0-13.4-10.1-26.8-26.8-26.8-16.8 0-26.8 10.1-26.8 26.8L775 798.5v13.4c0 23.5-10.1 43.6-30.2 53.7-13.4 6.7-30.2 10.1-50.3 10.1H332.3c-33.5 3.4-60.4 0-70.4-33.5-3.4-6.7-6.7-16.8-6.7-26.8l-10.1-104-36.9-322c0-13.4-10.1-23.5-23.5-23.5s-26.8 10.1-26.8 23.5l47 462.8c0 40.2 40.2 73.8 80.5 73.8h459.5c40.2 0 80.5-33.5 80.5-73.8l36.8-462.8c0 3.3 0 0 0 0z m0 0"
+                p-id="12416"></path>
+            </svg>
+          </span>
+        </div>
+      </div>
+
+      <div class="ti_title">
+        <div class="ti_t_input" contenteditable="true" v-text="item.teststitle"
+          @blur="setTestTitle(item.id, $event.target.innerText)"></div>
+        <div class="uploadImage" @click="uploadImage(item.id)">
+          <svg viewBox="0 0 1024 1024" version="1.1" p-id="15953" width="200" height="200">
+            <path
+              d="M368 480c-62.4 0-112-49.6-112-112s49.6-112 112-112 112 49.6 112 112-49.6 112-112 112z m0-160c-27.2 0-48 20.8-48 48s20.8 48 48 48 48-20.8 48-48-20.8-48-48-48z m464 608H192c-52.8 0-96-43.2-96-96V192c0-52.8 43.2-96 96-96h640c52.8 0 96 43.2 96 96v640c0 52.8-43.2 96-96 96zM192 160c-17.6 0-32 14.4-32 32v640c0 17.6 14.4 32 32 32h640c17.6 0 32-14.4 32-32V192c0-17.6-14.4-32-32-32H192z m259.2 556.8c-25.6 0-51.2-11.2-70.4-30.4l-38.4-40c-12.8-12.8-33.6-12.8-46.4 0l-49.6 52.8c-12.8 12.8-32 12.8-44.8 1.6s-12.8-32-1.6-44.8l49.6-52.8c17.6-19.2 43.2-30.4 68.8-30.4s51.2 11.2 70.4 30.4l38.4 40c12.8 12.8 33.6 12.8 46.4 0l160-168c17.6-19.2 43.2-30.4 70.4-30.4s51.2 11.2 70.4 30.4L920 628.8c12.8 12.8 11.2 33.6-1.6 44.8-12.8 12.8-33.6 11.2-44.8-1.6L728 518.4c-12.8-12.8-33.6-12.8-46.4 0L521.6 688c-19.2 17.6-44.8 28.8-70.4 28.8z"
+              fill="#333333" p-id="15954"></path>
+          </svg>
+        </div>
+      </div>
+      <!-- 图片 -->
+      <div class="imageList">
+        <div v-for="(image, imageIndex) in item.timuList" :key="item.id+'_'+imageIndex">
+          <el-image style="width: 100px; height: 100px" :src="image.url" :preview-src-list="[image.url]"
+            fit="cover"></el-image>
+            <svg @click="delImage(item.id, imageIndex)" t="1774237005199" viewBox="0 0 1024 1024" width="200" height="200"><path d="M512 1024A512 512 0 1 1 512 0a512 512 0 0 1 0 1024zM305.956571 370.395429L447.488 512 305.956571 653.604571a45.568 45.568 0 1 0 64.438858 64.438858L512 576.512l141.604571 141.531429a45.568 45.568 0 0 0 64.438858-64.438858L576.512 512l141.531429-141.604571a45.568 45.568 0 1 0-64.438858-64.438858L512 447.488 370.395429 305.956571a45.568 45.568 0 0 0-64.438858 64.438858z" fill="#FF2525" p-id="4716"></path></svg>
+        </div>
+      </div>
+
+      <!-- 选择题 -->
+      <div class="checkList">
+        <div class="checkItem" v-for="(check, checkIndex) in item.checkList" :key="checkIndex">
+          <div class="check" :class="{ 'checked': item.answer.includes(checkIndex) }"
+            @click="checkClick(item.id, checkIndex)">
+            <svg v-if="item.answer.includes(checkIndex)" t="1773996159000" viewBox="0 0 1024 1024" version="1.1"
+              xmlns="http://www.w3.org/2000/svg" p-id="5894" width="200" height="200">
+              <path
+                d="M404.352 685.354667L789.632 213.333333 853.333333 267.52 409.941333 810.666667 170.666667 566.4l58.581333-59.818667z"
+                p-id="5895"></path>
+            </svg>
+          </div>
+          <el-input v-model="item.checkList[checkIndex]" :placeholder="lang.ssEnterOption" @blur="setTestJson()"></el-input>
+          <div class="btn">
+            <div @click="delCheck(item.id, checkIndex)">
+              <svg viewBox="0 0 1024 1024" version="1.1" p-id="12415" width="200" height="200">
+                <path
+                  d="M902.4 282.1H117.7c-13.4 0-23.5-10.1-23.5-23.5v-3.4c0-13.4 10.1-23.5 23.5-23.5h788.1c13.4 0 23.5 10.1 23.5 23.5v3.4c0 13.4-10.1 23.5-26.9 23.5zM634.1 151.3H386c-13.4 0-26.8-10.1-23.5-23.5v-6.7c0-13.4 10.1-23.5 23.5-23.5h248.2c13.4 0 23.5 10.1 23.5 23.5v3.4c3.3 13.3-10.1 26.8-23.6 26.8z m228.1 238.1c0-13.4-10.1-26.8-26.8-26.8-16.8 0-26.8 10.1-26.8 26.8L775 798.5v13.4c0 23.5-10.1 43.6-30.2 53.7-13.4 6.7-30.2 10.1-50.3 10.1H332.3c-33.5 3.4-60.4 0-70.4-33.5-3.4-6.7-6.7-16.8-6.7-26.8l-10.1-104-36.9-322c0-13.4-10.1-23.5-23.5-23.5s-26.8 10.1-26.8 23.5l47 462.8c0 40.2 40.2 73.8 80.5 73.8h459.5c40.2 0 80.5-33.5 80.5-73.8l36.8-462.8c0 3.3 0 0 0 0z m0 0"
+                  p-id="12416"></path>
+              </svg>
+            </div>
+          </div>
+        </div>
+        <div class="addCheck" @click="addCheck(item.id)">
+          <svg viewBox="0 0 1024 1024" version="1.1" p-id="2732" width="200" height="200">
+            <path
+              d="M925.696 384q19.456 0 37.376 7.68t30.72 20.48 20.48 30.72 7.68 37.376q0 20.48-7.68 37.888t-20.48 30.208-30.72 20.48-37.376 7.68l-287.744 0 0 287.744q0 20.48-7.68 37.888t-20.48 30.208-30.72 20.48-37.376 7.68q-20.48 0-37.888-7.68t-30.208-20.48-20.48-30.208-7.68-37.888l0-287.744-287.744 0q-20.48 0-37.888-7.68t-30.208-20.48-20.48-30.208-7.68-37.888q0-19.456 7.68-37.376t20.48-30.72 30.208-20.48 37.888-7.68l287.744 0 0-287.744q0-19.456 7.68-37.376t20.48-30.72 30.208-20.48 37.888-7.68q39.936 0 68.096 28.16t28.16 68.096l0 287.744 287.744 0z"
+              p-id="2733"></path>
+          </svg>
+          <span>{{ lang.ssOption }}</span>
+        </div>
+      </div>
+
+      <!-- 解释说明 -->
+      <div class="explanation">
+        <div class="e_header">
+          <span>{{ lang.ssExplanationTip }}</span>
+          <div v-show="false">
+            <svg t="1774233113566" viewBox="0 0 1027 1024" width="200" height="200">
+              <path
+                d="M511.979521 544.586217a54.525819 54.525819 0 0 1-23.359066-5.247791L31.038758 321.427143a54.397824 54.397824 0 0 1 0-98.236071L488.620455 5.279789c14.719411-7.039718 31.99872-7.039718 46.718131 0l457.581697 217.911283a54.397824 54.397824 0 0 1 0 98.236071l-457.581697 217.911283A54.525819 54.525819 0 0 1 511.979521 544.586217zM180.984761 272.341106L511.979521 429.966801l331.058757-157.625695L511.979521 114.587417 180.984761 272.341106z m354.417823 746.402144l457.517699-217.911283a54.397824 54.397824 0 1 0-46.718131-98.236071L511.979521 909.371625l-434.158634-206.775729a54.397824 54.397824 0 0 0-46.718131 98.236071l457.581697 217.911283a54.525819 54.525819 0 0 0 46.718131 0z m0-239.73441l457.517699-217.847286a54.397824 54.397824 0 1 0-46.718131-98.300068L511.979521 669.573217l-434.158634-206.711731a54.397824 54.397824 0 0 0-46.718131 98.300068l457.581697 217.847286a54.525819 54.525819 0 0 0 46.718131 0z"
+                p-id="9073"></path>
+            </svg>
+            <span>{{ lang.ssAIGenerate }}</span>
+          </div>
+        </div>
+        <el-input type="textarea" rows="3" resize="none" v-model="item.explanation" :placeholder="lang.ssEnterExplanation"
+          @blur="setTestJson()"></el-input>
+      </div>
+    </div>
+
+
+    <!-- 添加题目 -->
+    <div class="addTest" @click="addTest()">
+      <svg viewBox="0 0 1024 1024" version="1.1" p-id="2732" width="200" height="200">
+        <path
+          d="M925.696 384q19.456 0 37.376 7.68t30.72 20.48 20.48 30.72 7.68 37.376q0 20.48-7.68 37.888t-20.48 30.208-30.72 20.48-37.376 7.68l-287.744 0 0 287.744q0 20.48-7.68 37.888t-20.48 30.208-30.72 20.48-37.376 7.68q-20.48 0-37.888-7.68t-30.208-20.48-20.48-30.208-7.68-37.888l0-287.744-287.744 0q-20.48 0-37.888-7.68t-30.208-20.48-20.48-30.208-7.68-37.888q0-19.456 7.68-37.376t20.48-30.72 30.208-20.48 37.888-7.68l287.744 0 0-287.744q0-19.456 7.68-37.376t20.48-30.72 30.208-20.48 37.888-7.68q39.936 0 68.096 28.16t28.16 68.096l0 287.744 287.744 0z"
+          p-id="2733"></path>
+      </svg>
+      <span>{{ lang.ssTopic }}</span>
+    </div>
+
+  </div>
+</template>
+
+<script>
+import { v4 as uuidv4 } from 'uuid';
+import { uploadOneFile } from '@/components/tools/uploadFile'
+export default {
+  emits: ['setTestJson', 'save'],
+  props: {
+    workData: {
+      type: Object,
+      default: () => { }
+    }
+  },
+  data() {
+    return {
+      jsonData: {}
+    }
+  },
+  watch: {
+    workData: {
+      handler(newVal, oldVal) {
+        if (newVal.type == 45) {
+          if (JSON.stringify(newVal.json) != JSON.stringify(this.jsonData)) {
+            this.jsonData = JSON.parse(JSON.stringify(newVal.json));
+          }
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  methods: {
+    // 更新题目
+    setTestJson() {
+      // console.log(this.jsonData)
+      this.jsonData.testCount = this.jsonData.testJson.length;
+      this.$emit('setTestJson', this.jsonData);
+    },
+    // 添加题目
+    addTest() {
+      this.jsonData.testJson.push({
+        id: uuidv4(),
+        type: "2",
+        teststitle: "",
+        checkList: [''],
+        timuList: [],
+        answer: [],
+        userAnswer: [],
+        explanation: '',
+      });
+      this.setTestJson();
+    },
+    //修改标题
+    setTestTitle(id, title) {
+      console.log('修改标题', id, title)
+      let test = this.jsonData.testJson.find(item => item.id == id);
+      if (test) {
+        test.teststitle = title;
+      }
+      this.setTestJson();
+    },
+    // 点击复选框
+    checkClick(id, index) {
+      let test = this.jsonData.testJson.find(item => item.id == id);
+      if (test) {
+        if (test.answer.includes(index)) {
+          test.answer.splice(test.answer.indexOf(index), 1);
+        } else {
+          test.answer.push(index);
+        }
+      }
+      this.setTestJson();
+    },
+    // 删除题目
+    deleteTest(id) {
+      let index = this.jsonData.testJson.findIndex(item => item.id == id);
+      this.jsonData.testJson.splice(index, 1);
+      this.setTestJson();
+    },
+    // 添加选项
+    addCheck(id) {
+      let index = this.jsonData.testJson.findIndex(item => item.id == id);
+      let test = this.jsonData.testJson[index];
+      test.checkList.push('');
+      this.setTestJson();
+    },
+    // 删除选项
+    delCheck(id, index) {
+      let test = this.jsonData.testJson.find(item => item.id == id);
+      if (test) {
+        if (test.checkList.length == 1) {
+          this.$message.error("至少保留一个选项");
+          return;
+        }
+        test.checkList.splice(index, 1);
+      }
+      this.setTestJson();
+    },
+    // 上传图片
+    uploadImage(id) {
+      const input = document.createElement('input');
+      input.type = 'file';
+      input.accept = 'image/*';
+      input.click();
+      input.onchange = (e) => {
+        if (e.target.files[0]) {
+          uploadOneFile(e.target.files[0]).then(res => {
+            res.src = res.url
+            this.jsonData.testJson.find(item => item.id == id).timuList = [res];
+            this.setTestJson();
+          })
+        }
+      }
+    },
+    // 复制题目
+    copyTest(id) {
+      let test = this.jsonData.testJson.find(item => item.id == id);
+      if (test) {
+        test = JSON.parse(JSON.stringify(test));
+        test.id = uuidv4();
+        this.jsonData.testJson.push(test);
+        this.setTestJson();
+      }
+    },
+    // 删除图片
+    delImage(id, index) {
+      let test = this.jsonData.testJson.find(item => item.id == id);
+      if (test) {
+        test.timuList.splice(index, 1);
+      }
+      this.setTestJson();
+    },
+  },
+}
+</script>
+
+<style scoped>
+.setChoiceQuestion {
+  width: 100%;
+  height: auto;
+  background: #fff;
+  display: flex;
+  flex-direction: column;
+  overflow: auto;
+  padding: 4rem;
+  box-sizing: border-box;
+  gap: 2rem;
+}
+
+.addTest {
+  border-radius: 5px;
+  border: 1px dashed #d1d5db;
+  padding: .5rem 1rem;
+  height: fit-content;
+  width: fit-content;
+  display: flex;
+  align-items: center;
+  gap: .5rem;
+  cursor: pointer;
+}
+
+.addTest>svg {
+  width: .7rem;
+  height: .7rem;
+  fill: #6E7583;
+}
+
+.addTest>span {
+  font-weight: bold;
+  font-size: .9rem;
+  color: #6b7280;
+}
+
+.testItem {
+  width: 100%;
+  height: auto;
+  display: flex;
+  align-items: center;
+  gap: 1rem;
+  flex-direction: column;
+}
+
+.ti_header {
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+
+}
+
+.ti_header>span {
+  font-size: 1rem;
+  font-weight: 600;
+  color: #ff9300;
+}
+
+.ti_h_edit {
+  display: flex;
+  align-items: center;
+  gap: 1rem;
+}
+
+.ti_h_edit>span {
+  width: 1.5rem;
+  height: 1.5rem;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: #F9FAFB;
+  border-radius: 4px;
+  cursor: pointer;
+}
+
+.ti_h_edit>span>svg {
+  width: 1rem;
+  height: 1rem;
+  fill: #6B7280;
+}
+
+.ti_title {
+  width: 100%;
+  height: fit-content;
+  padding-bottom: 2rem;
+  min-height: 4rem;
+  background: #FAFBFC;
+  border-radius: 8px;
+  border: 1px solid #E5E7EB;
+  position: relative;
+}
+
+.ti_t_input {
+  width: 100%;
+  height: 100%;
+  padding: 1rem;
+  box-sizing: border-box;
+  border: none;
+  outline: none;
+  background: none;
+  font-size: .8rem;
+  resize: none;
+  /* padding-right: 2rem; */
+}
+
+.uploadImage {
+  position: absolute;
+  bottom: 0.5rem;
+  right: 0.5rem;
+  background: #fff;
+  border-radius: .5rem;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  border: 1px solid #E5E7EB;
+  cursor: pointer;
+  padding: .5rem;
+}
+
+.uploadImage>svg {
+  width: 1rem;
+  height: 1rem;
+}
+
+.checkList {
+  width: 100%;
+  height: auto;
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+  padding-left: 4rem;
+}
+
+.checkItem {
+  width: 100%;
+  height: auto;
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  gap: .5rem;
+
+}
+
+.check {
+  width: 1.1rem;
+  height: 1.1rem;
+  border: solid 1px #D1D5DB;
+  border-radius: .25rem;
+  cursor: pointer;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.checked {
+  background: #FF9300;
+}
+
+.checked>svg {
+  width: .7rem;
+  height: .7rem;
+  fill: #fff;
+}
+
+.checkItem>.el-input {
+  width: calc(100% - 10rem);
+}
+
+.addCheck {
+  border-radius: 5px;
+  border: 1px dashed #d1d5db;
+  padding: .3rem .8rem;
+  height: fit-content;
+  width: fit-content;
+  display: flex;
+  align-items: center;
+  gap: .5rem;
+  cursor: pointer;
+  margin-left: 2.2rem;
+}
+
+.addCheck>svg {
+  width: .5rem;
+  height: .5rem;
+  fill: #6E7583;
+}
+
+.addCheck>span {
+  font-weight: bold;
+  font-size: .8rem;
+  color: #6b7280;
+}
+
+.btn {
+  display: flex;
+  align-items: center;
+  gap: .25em;
+}
+
+.btn>div {
+  width: 1.5rem;
+  height: 1.5rem;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background: #F9FAFB;
+  border-radius: .4px;
+  cursor: pointer;
+}
+
+.btn>div>svg {
+  width: 1rem;
+  height: 1rem;
+  fill: #6B7280;
+}
+
+.explanation {
+  width: 100%;
+  height: auto;
+  padding: 1rem;
+  background: #FAFBFC;
+  border-radius: 5px;
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+  border-radius: .8rem;
+}
+
+.e_header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.e_header>span {
+  color: #6b7280;
+  font-size: .8rem;
+  font-weight: 500;
+}
+
+.e_header>div {
+  display: flex;
+  align-items: center;
+  gap: .5rem;
+  background: #ff9300;
+  color: #fff;
+  padding: .3rem .8rem;
+  font-size: .8rem;
+  font-weight: 500;
+  border-radius: .5rem;
+  cursor: pointer;
+}
+
+.e_header>div>svg {
+  width: .8rem;
+  height: .8rem;
+  fill: #fff;
+}
+
+.imageList {
+  width: 100%;
+  height: auto;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 1rem;
+}
+.imageList>div{
+  width: 100px;
+  height: 100px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  /* overflow: hidden; */
+  border-radius: .5rem;
+  position: relative;
+
+}
+
+.imageList>div:hover>svg{
+  display: flex;
+}
+
+.imageList>div>svg{
+  width: 1rem;
+  height: 1rem;
+  position: absolute;
+  top: -.3rem;
+  right: -.3rem;
+  font-weight: 500;
+  border-radius: .5rem;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  display: none;
+}
+
+
+
+</style>

+ 465 - 0
src/components/pages/workPage/components/setQuestionsAndAnswers.vue

@@ -0,0 +1,465 @@
+<template>
+  <div class="setChoiceQuestion">
+    <div class="testItem">
+      <div class="ti_header">
+        <span>{{ lang.ssTopic }}{{ 1 }}</span>
+      </div>
+
+      <div class="ti_title">
+        <div class="ti_t_input" contenteditable="true" v-text="jsonData.answerQ"
+          @blur="setTestTitle($event.target.innerText)"></div>
+        <div class="uploadImage" @click="uploadImage()">
+          <svg viewBox="0 0 1024 1024" version="1.1" p-id="15953" width="200" height="200">
+            <path
+              d="M368 480c-62.4 0-112-49.6-112-112s49.6-112 112-112 112 49.6 112 112-49.6 112-112 112z m0-160c-27.2 0-48 20.8-48 48s20.8 48 48 48 48-20.8 48-48-20.8-48-48-48z m464 608H192c-52.8 0-96-43.2-96-96V192c0-52.8 43.2-96 96-96h640c52.8 0 96 43.2 96 96v640c0 52.8-43.2 96-96 96zM192 160c-17.6 0-32 14.4-32 32v640c0 17.6 14.4 32 32 32h640c17.6 0 32-14.4 32-32V192c0-17.6-14.4-32-32-32H192z m259.2 556.8c-25.6 0-51.2-11.2-70.4-30.4l-38.4-40c-12.8-12.8-33.6-12.8-46.4 0l-49.6 52.8c-12.8 12.8-32 12.8-44.8 1.6s-12.8-32-1.6-44.8l49.6-52.8c17.6-19.2 43.2-30.4 68.8-30.4s51.2 11.2 70.4 30.4l38.4 40c12.8 12.8 33.6 12.8 46.4 0l160-168c17.6-19.2 43.2-30.4 70.4-30.4s51.2 11.2 70.4 30.4L920 628.8c12.8 12.8 11.2 33.6-1.6 44.8-12.8 12.8-33.6 11.2-44.8-1.6L728 518.4c-12.8-12.8-33.6-12.8-46.4 0L521.6 688c-19.2 17.6-44.8 28.8-70.4 28.8z"
+              fill="#333333" p-id="15954"></path>
+          </svg>
+        </div>
+      </div>
+      <!-- 图片 -->
+      <div class="imageList">
+        <div v-for="(image, imageIndex) in jsonData.imageList" :key="imageIndex">
+          <el-image style="width: 100px; height: 100px" :src="image.url" :preview-src-list="[image.url]"
+            fit="cover"></el-image>
+            <svg @click="delImage(imageIndex)" t="1774237005199" viewBox="0 0 1024 1024" width="200" height="200"><path d="M512 1024A512 512 0 1 1 512 0a512 512 0 0 1 0 1024zM305.956571 370.395429L447.488 512 305.956571 653.604571a45.568 45.568 0 1 0 64.438858 64.438858L512 576.512l141.604571 141.531429a45.568 45.568 0 0 0 64.438858-64.438858L576.512 512l141.531429-141.604571a45.568 45.568 0 1 0-64.438858-64.438858L512 447.488 370.395429 305.956571a45.568 45.568 0 0 0-64.438858 64.438858z" fill="#FF2525" p-id="4716"></path></svg>
+        </div>
+      </div>
+
+      <!-- 选择题 -->
+      <!-- <div class="checkList">
+        <div class="checkItem" v-for="(check, checkIndex) in item.checkList" :key="checkIndex">
+          <div class="check" :class="{ 'checked': item.answer.includes(checkIndex) }"
+            @click="checkClick(item.id, checkIndex)">
+            <svg v-if="item.answer.includes(checkIndex)" t="1773996159000" viewBox="0 0 1024 1024" version="1.1"
+              xmlns="http://www.w3.org/2000/svg" p-id="5894" width="200" height="200">
+              <path
+                d="M404.352 685.354667L789.632 213.333333 853.333333 267.52 409.941333 810.666667 170.666667 566.4l58.581333-59.818667z"
+                p-id="5895"></path>
+            </svg>
+          </div>
+          <el-input v-model="item.checkList[checkIndex]" placeholder="请输入选项" @blur="setTestJson()"></el-input>
+          <div class="btn">
+            <div @click="delCheck(item.id, checkIndex)">
+              <svg viewBox="0 0 1024 1024" version="1.1" p-id="12415" width="200" height="200">
+                <path
+                  d="M902.4 282.1H117.7c-13.4 0-23.5-10.1-23.5-23.5v-3.4c0-13.4 10.1-23.5 23.5-23.5h788.1c13.4 0 23.5 10.1 23.5 23.5v3.4c0 13.4-10.1 23.5-26.9 23.5zM634.1 151.3H386c-13.4 0-26.8-10.1-23.5-23.5v-6.7c0-13.4 10.1-23.5 23.5-23.5h248.2c13.4 0 23.5 10.1 23.5 23.5v3.4c3.3 13.3-10.1 26.8-23.6 26.8z m228.1 238.1c0-13.4-10.1-26.8-26.8-26.8-16.8 0-26.8 10.1-26.8 26.8L775 798.5v13.4c0 23.5-10.1 43.6-30.2 53.7-13.4 6.7-30.2 10.1-50.3 10.1H332.3c-33.5 3.4-60.4 0-70.4-33.5-3.4-6.7-6.7-16.8-6.7-26.8l-10.1-104-36.9-322c0-13.4-10.1-23.5-23.5-23.5s-26.8 10.1-26.8 23.5l47 462.8c0 40.2 40.2 73.8 80.5 73.8h459.5c40.2 0 80.5-33.5 80.5-73.8l36.8-462.8c0 3.3 0 0 0 0z m0 0"
+                  p-id="12416"></path>
+              </svg>
+            </div>
+          </div>
+        </div>
+        <div class="addCheck" @click="addCheck(item.id)">
+          <svg viewBox="0 0 1024 1024" version="1.1" p-id="2732" width="200" height="200">
+            <path
+              d="M925.696 384q19.456 0 37.376 7.68t30.72 20.48 20.48 30.72 7.68 37.376q0 20.48-7.68 37.888t-20.48 30.208-30.72 20.48-37.376 7.68l-287.744 0 0 287.744q0 20.48-7.68 37.888t-20.48 30.208-30.72 20.48-37.376 7.68q-20.48 0-37.888-7.68t-30.208-20.48-20.48-30.208-7.68-37.888l0-287.744-287.744 0q-20.48 0-37.888-7.68t-30.208-20.48-20.48-30.208-7.68-37.888q0-19.456 7.68-37.376t20.48-30.72 30.208-20.48 37.888-7.68l287.744 0 0-287.744q0-19.456 7.68-37.376t20.48-30.72 30.208-20.48 37.888-7.68q39.936 0 68.096 28.16t28.16 68.096l0 287.744 287.744 0z"
+              p-id="2733"></path>
+          </svg>
+          <span>选项</span>
+        </div>
+      </div> -->
+
+      <!-- 解释说明 -->
+      <div class="explanation">
+        <div class="e_header">
+          <span>{{ lang.ssEvaluationStandard }}</span>
+          <!-- <div v-show="false">
+            <svg t="1774233113566" viewBox="0 0 1027 1024" width="200" height="200">
+              <path
+                d="M511.979521 544.586217a54.525819 54.525819 0 0 1-23.359066-5.247791L31.038758 321.427143a54.397824 54.397824 0 0 1 0-98.236071L488.620455 5.279789c14.719411-7.039718 31.99872-7.039718 46.718131 0l457.581697 217.911283a54.397824 54.397824 0 0 1 0 98.236071l-457.581697 217.911283A54.525819 54.525819 0 0 1 511.979521 544.586217zM180.984761 272.341106L511.979521 429.966801l331.058757-157.625695L511.979521 114.587417 180.984761 272.341106z m354.417823 746.402144l457.517699-217.911283a54.397824 54.397824 0 1 0-46.718131-98.236071L511.979521 909.371625l-434.158634-206.775729a54.397824 54.397824 0 0 0-46.718131 98.236071l457.581697 217.911283a54.525819 54.525819 0 0 0 46.718131 0z m0-239.73441l457.517699-217.847286a54.397824 54.397824 0 1 0-46.718131-98.300068L511.979521 669.573217l-434.158634-206.711731a54.397824 54.397824 0 0 0-46.718131 98.300068l457.581697 217.847286a54.525819 54.525819 0 0 0 46.718131 0z"
+                p-id="9073"></path>
+            </svg>
+            <span>AI生成</span>
+          </div> -->
+        </div>
+        <el-input type="textarea" rows="3" resize="none" v-model="jsonData.evaluationCriteria" :placeholder="lang.ssEnterEvaluationStandard"
+          @blur="setTestJson()"></el-input>
+      </div>
+    </div>
+
+  </div>
+</template>
+
+<script>
+import { uploadOneFile } from '@/components/tools/uploadFile'
+export default {
+  emits: ['setTestJson', 'save'],
+  props: {
+    workData: {
+      type: Object,
+      default: () => { }
+    }
+  },
+  data() {
+    return {
+      jsonData: {}
+    }
+  },
+  watch: {
+    workData: {
+      handler(newVal, oldVal) {
+        if (newVal.type == 15) {
+          if (JSON.stringify(newVal.json) != JSON.stringify(this.jsonData)) {
+            let _data = JSON.parse(JSON.stringify(newVal.json))
+
+            if(!_data.imageList){
+              _data.imageList = [];
+            }
+            if(!_data.evaluationCriteria){
+              _data.evaluationCriteria = '';
+            }
+
+            this.jsonData = _data;
+          }
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  methods: {
+    // 更新题目
+    setTestJson() {
+      // console.log(this.jsonData)
+      // this.jsonData.testCount = this.jsonData.testJson.length;
+      this.$emit('setTestJson', this.jsonData);
+    },
+    //修改标题
+    setTestTitle( title) {
+      console.log('修改标题', title)
+      this.jsonData.answerQ = title;
+      // let test = this.jsonData..find(item => item.id == id);
+      // if (test) {
+      //   test.teststitle = title;
+      // }
+      this.setTestJson();
+    },
+    // 上传图片
+    uploadImage(id) {
+      const input = document.createElement('input');
+      input.type = 'file';
+      input.accept = 'image/*';
+      input.click();
+      input.onchange = (e) => {
+        if (e.target.files[0]) {
+          uploadOneFile(e.target.files[0]).then(res => {
+            res.src = res.url
+            this.jsonData.imageList = [res];
+            // this.jsonData.testJson.find(item => item.id == id).timuList = [res];
+            this.setTestJson();
+          })
+        }
+      }
+    },
+    // 删除图片
+    delImage(index) {
+      this.jsonData.imageList.splice(index, 1);
+      // let test = this.jsonData.testJson.find(item => item.id == id);
+      // if (test) {
+      //   test.timuList.splice(index, 1);
+      // }
+      this.setTestJson();
+    },
+  },
+}
+</script>
+
+<style scoped>
+.setChoiceQuestion {
+  width: 100%;
+  height: auto;
+  background: #fff;
+  display: flex;
+  flex-direction: column;
+  overflow: auto;
+  padding: 4rem;
+  box-sizing: border-box;
+  gap: 2rem;
+}
+
+.addTest {
+  border-radius: 5px;
+  border: 1px dashed #d1d5db;
+  padding: .5rem 1rem;
+  height: fit-content;
+  width: fit-content;
+  display: flex;
+  align-items: center;
+  gap: .5rem;
+  cursor: pointer;
+}
+
+.addTest>svg {
+  width: .7rem;
+  height: .7rem;
+  fill: #6E7583;
+}
+
+.addTest>span {
+  font-weight: bold;
+  font-size: .9rem;
+  color: #6b7280;
+}
+
+.testItem {
+  width: 100%;
+  height: auto;
+  display: flex;
+  align-items: center;
+  gap: 1rem;
+  flex-direction: column;
+}
+
+.ti_header {
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+
+}
+
+.ti_header>span {
+  font-size: 1rem;
+  font-weight: 600;
+  color: #ff9300;
+}
+
+.ti_h_edit {
+  display: flex;
+  align-items: center;
+  gap: 1rem;
+}
+
+.ti_h_edit>span {
+  width: 1.5rem;
+  height: 1.5rem;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: #F9FAFB;
+  border-radius: 4px;
+  cursor: pointer;
+}
+
+.ti_h_edit>span>svg {
+  width: 1rem;
+  height: 1rem;
+  fill: #6B7280;
+}
+
+.ti_title {
+  width: 100%;
+  height: fit-content;
+  padding-bottom: 2rem;
+  min-height: 4rem;
+  background: #FAFBFC;
+  border-radius: 8px;
+  border: 1px solid #E5E7EB;
+  position: relative;
+}
+
+.ti_t_input {
+  width: 100%;
+  height: 100%;
+  padding: 1rem;
+  box-sizing: border-box;
+  border: none;
+  outline: none;
+  background: none;
+  font-size: .8rem;
+  resize: none;
+  /* padding-right: 2rem; */
+}
+
+.uploadImage {
+  position: absolute;
+  bottom: 0.5rem;
+  right: 0.5rem;
+  background: #fff;
+  border-radius: .5rem;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  border: 1px solid #E5E7EB;
+  cursor: pointer;
+  padding: .5rem;
+}
+
+.uploadImage>svg {
+  width: 1rem;
+  height: 1rem;
+}
+
+.checkList {
+  width: 100%;
+  height: auto;
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+  padding-left: 4rem;
+}
+
+.checkItem {
+  width: 100%;
+  height: auto;
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  gap: .5rem;
+
+}
+
+.check {
+  width: 1.1rem;
+  height: 1.1rem;
+  border: solid 1px #D1D5DB;
+  border-radius: .25rem;
+  cursor: pointer;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.checked {
+  background: #FF9300;
+}
+
+.checked>svg {
+  width: .7rem;
+  height: .7rem;
+  fill: #fff;
+}
+
+.checkItem>.el-input {
+  width: calc(100% - 10rem);
+}
+
+.addCheck {
+  border-radius: 5px;
+  border: 1px dashed #d1d5db;
+  padding: .3rem .8rem;
+  height: fit-content;
+  width: fit-content;
+  display: flex;
+  align-items: center;
+  gap: .5rem;
+  cursor: pointer;
+  margin-left: 2.2rem;
+}
+
+.addCheck>svg {
+  width: .5rem;
+  height: .5rem;
+  fill: #6E7583;
+}
+
+.addCheck>span {
+  font-weight: bold;
+  font-size: .8rem;
+  color: #6b7280;
+}
+
+.btn {
+  display: flex;
+  align-items: center;
+  gap: .25em;
+}
+
+.btn>div {
+  width: 1.5rem;
+  height: 1.5rem;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background: #F9FAFB;
+  border-radius: .4px;
+  cursor: pointer;
+}
+
+.btn>div>svg {
+  width: 1rem;
+  height: 1rem;
+  fill: #6B7280;
+}
+
+.explanation {
+  width: 100%;
+  height: auto;
+  padding: 1rem;
+  background: #FAFBFC;
+  border-radius: 5px;
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+  border-radius: .8rem;
+}
+
+.e_header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.e_header>span {
+  color: #6b7280;
+  font-size: .8rem;
+  font-weight: 500;
+}
+
+.e_header>div {
+  display: flex;
+  align-items: center;
+  gap: .5rem;
+  background: #ff9300;
+  color: #fff;
+  padding: .3rem .8rem;
+  font-size: .8rem;
+  font-weight: 500;
+  border-radius: .5rem;
+  cursor: pointer;
+}
+
+.e_header>div>svg {
+  width: .8rem;
+  height: .8rem;
+  fill: #fff;
+}
+
+.imageList {
+  width: 100%;
+  height: auto;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 1rem;
+}
+.imageList>div{
+  width: 100px;
+  height: 100px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  /* overflow: hidden; */
+  border-radius: .5rem;
+  position: relative;
+
+}
+
+.imageList>div:hover>svg{
+  display: flex;
+}
+
+.imageList>div>svg{
+  width: 1rem;
+  height: 1rem;
+  position: absolute;
+  top: -.3rem;
+  right: -.3rem;
+  font-weight: 500;
+  border-radius: .5rem;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  display: none;
+}
+
+</style>

+ 110 - 0
src/components/pages/workPage/setIndex.vue

@@ -0,0 +1,110 @@
+<template>
+  <div class="setWorkPage">
+    <!-- 选择题设置 -->
+    <setChoiceQuestion :workData="workData" v-if="workData.type == 45" @setTestJson="setTestJson" @save="saveTest"/>
+    <setQuestionsAndAnswers :workData="workData" v-if="workData.type == 15" @setTestJson="setTestJson" @save="saveTest"/>
+  </div>
+</template>
+
+<script>
+import setChoiceQuestion from './components/setChoiceQuestion.vue'
+import setQuestionsAndAnswers from './components/setQuestionsAndAnswers.vue'
+export default {
+  components: {
+    setChoiceQuestion,
+    setQuestionsAndAnswers
+  },
+  data() {
+    return {
+      id: this.$route.query.id,
+      courseid: this.$route.query.courseid,
+      userid: this.$route.query.userid,
+      oid: this.$route.query.oid,
+      org: this.$route.query.org,
+      role: this.$route.query.role,
+      stage: this.$route.query.stage,
+      task: this.$route.query.task,
+      tool: this.$route.query.tool,
+      type: "",
+      cid: this.$route.query.cid,
+      workData: {},
+      loading: false
+    }
+  },
+  methods: {
+    getWorkData() {
+      if (!this.id) return console.log("无作业id");
+      let params = {
+        id: this.id
+      };
+      this.loading = true;
+      this.ajax
+        .get(this.$store.state.api + "select_workPageById", params)
+        .then(res => {
+          let _data = res.data[0];
+          if (_data.length) {
+            _data = _data[0];
+            _data.json = JSON.parse(_data.json);
+            if (_data.type == 15) {
+              _data.json.answer = "";
+              _data.json.fileList = [];
+            } else if (_data.type == 45) {
+              _data.json.testJson.forEach(item => {
+                if (item.type == "2") {
+                  item.userAnswer = [];
+                } else if (item.type == "1") {
+                  item.userAnswer = "";
+                }
+              });
+            }
+            this.type = _data.type;
+
+            this.workData = _data;
+
+          }
+          this.loading = false
+        }).catch((err) => {
+          console.log(err);
+          this.loading = false;
+        });
+    },
+    // 设置选择题
+    setTestJson(newVal){
+      this.workData.json = JSON.parse(JSON.stringify(newVal));
+      this.saveTest();
+    },
+    // 保存
+    saveTest(){
+      const params = [{
+        uid: this.userid || '',
+        id: this.workData.id,
+        json: JSON.stringify(this.workData.json),
+      }]
+
+      this.ajax.post(this.$store.state.api + "updata_workPage_json", params).then(res => {
+        if (res.data == 200) {
+          console.log("保存成功")
+          // this.$message.success("保存成功");
+        }
+      }).catch((err) => {
+        console.log("保存失败",err);
+        // this.$message.error("保存失败");
+      })
+    }
+  },
+  mounted() {
+    this.getWorkData();
+  }
+}
+</script>
+
+<style scoped>
+.setWorkPage {
+  width: 100%;
+  height: 100%;
+  /* height: auto; */
+  background: #fff;
+  box-sizing: border-box;
+  overflow-x: hidden;
+}
+</style>

+ 519 - 0
src/components/tools/uploadFile.js

@@ -0,0 +1,519 @@
+import '../../common/aws-sdk-2.235.1.min.js'
+import { v4 as uuidv4 } from 'uuid'
+
+
+
+// 上传单个文件
+const uploadOneFile = (file, progressFn) => {
+  return new Promise((resolve) => {
+    let credentials = {
+      accessKeyId: 'AKIATLPEDU37QV5CHLMH',
+      secretAccessKey: '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',
+    } //秘钥形式的登录上传
+    window.AWS.config.update(credentials)
+    window.AWS.config.region = 'cn-northwest-1' //设置区域
+
+    let bucket = new window.AWS.S3({ params: { Bucket: 'ccrb' } }) //选择桶
+    if (file) {
+      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) {
+          //这里可以写进度条
+          if (progressFn) {
+            let _progress = {
+              loaded:evt.loaded,
+              total:evt.total,
+              percent:(evt.loaded/evt.total*100).toFixed(2),
+            }
+            progressFn(_progress)
+          }
+        })
+        .send(function (err, data) {
+          if (err) {
+            resolve('')
+          } else {
+            let fileObj = {
+              name: file.name,
+              url: data.Location,
+              size: formatFileSize(file.size), // 格式化文件大小
+              uid: uuidv4(),
+              type: file.type,
+              fileType:getFileType(file),
+            }
+            console.log('uploadFile', fileObj)
+            resolve(fileObj)
+          }
+        })
+    }
+  })
+}
+
+// 获取文件数据
+const getFile = (url) => {
+  return new Promise((resolve) => {
+    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 {
+        resolve({ data: data.Body });
+        console.log(data);
+      }          // sxuccessful response
+
+    });
+  });
+};
+
+const getTxtFileContent = (url) => {
+  return new Promise((resolve) => {
+    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 });
+      }
+    });
+  });
+}
+
+const formatFileSize = (size) => {
+  if (size < 1024) {
+    return size + 'B'
+  } else if (size < 1024 * 1024) {
+    return (size / 1024).toFixed(2) + 'KB'
+  } else if (size < 1024 * 1024 * 1024) {
+    return (size / (1024 * 1024)).toFixed(2) + 'MB'
+  } else if (size < 1024 * 1024 * 1024 * 1024) {
+    return (size / (1024 * 1024 * 1024)).toFixed(2) + 'GB'
+  } else {
+    return (size / (1024 * 1024 * 1024 * 1024)).toFixed(2) + 'TB'
+  }
+}
+
+// 常用文件类型清单
+const fileTypes = [
+  { value: 'image', label: '图片', exts: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'], mime: ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/webp', 'image/svg+xml'] },
+  { value: 'video', label: '视频', exts: ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm'], mime: ['video/mp4', 'video/x-msvideo', 'video/quicktime', 'video/x-ms-wmv', 'video/x-flv', 'video/x-matroska', 'video/webm'] },
+  { value: 'audio', label: '音频', exts: ['mp3', 'wav', 'aac', 'ogg', 'flac', 'm4a'], mime: ['audio/mpeg', 'audio/x-wav', 'audio/aac', 'audio/ogg', 'audio/flac', 'audio/mp4'] },
+  { value: 'doc', label: '文档', exts: ['doc', 'docx', 'pdf', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'md', 'csv'], mime: ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/pdf', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'text/plain', 'text/markdown', 'text/csv'] },
+  { value: 'zip', label: '压缩包', exts: ['zip', 'rar', '7z', 'tar', 'gz'], mime: ['application/zip', 'application/x-rar-compressed', 'application/x-7z-compressed', 'application/x-tar', 'application/gzip'] },
+  { value: 'other', label: '其它', exts: [], mime: [] }
+]
+
+// 根据传入的文件类型(文件名/后缀或mime)获取value
+const getFileType = (file) => {
+  if (!file) return 'other';
+  let ext = '';
+  let mime = '';
+
+  // 允许传入 string 或 File/Blob 对象
+  if (typeof file === 'string') {
+    // 从文件名里提取后缀
+    const match = file.match(/\.([^.]+)$/);
+    ext = match ? match[1].toLowerCase() : '';
+  } else if (typeof file === 'object' && file) {
+    // File 或 Blob 情况,取type为mime,name取后缀
+    if (file.type) mime = file.type;
+    if (file.name) {
+      const match = file.name.match(/\.([^.]+)$/);
+      ext = match ? match[1].toLowerCase() : '';
+    }
+  }
+
+  // 先按mime类型查找
+  if (mime) {
+    for (let type of fileTypes) {
+      if (type.mime.includes(mime)) {
+        return type.value;
+      }
+    }
+  }
+  // 再按扩展名查找
+  if (ext) {
+    for (let type of fileTypes) {
+      if (type.exts.includes(ext)) {
+        return type.value;
+      }
+    }
+  }
+  // 未命中则返回other
+  return 'other';
+}
+
+// 分片上传
+/**
+ * AWS S3 分片上传工具,支持进度回调及停止上传功能
+ * 使用方式:
+ *   const uploader = new AwsMultipartUploader(options);
+ *   uploader.upload({ file, keyName, folderName, onProgress, onSuccess, onError });
+ *   uploader.stop(); // 随时可停止
+ */
+class AwsMultipartUploader {
+  constructor({
+    bucketname = "ccrb",
+    accessKeyId = "AKIATLPEDU37QV5CHLMH",
+    secretAccessKey = "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",
+    region = "cn-northwest-1",
+    partsize = 10 * 1024 * 1024 // 10MB
+  } = {}) {
+    this.bucketname = bucketname;
+    this.accessKeyId = accessKeyId;
+    this.secretAccessKey = secretAccessKey;
+    this.region = region;
+    this.partsize = partsize;
+    this.bucket = null;
+    this.flag = true;
+    this.uploadid = "";
+    this.lastFilestate = null; // 缓存上次的filestate, 避免重复回调
+  }
+
+  async init() {
+    const credentials = {
+      accessKeyId: this.accessKeyId,
+      secretAccessKey: this.secretAccessKey,
+      region: this.region
+    };
+    window.AWS.config.update(credentials);
+    this.bucket = new window.AWS.S3({ params: { Bucket: this.bucketname } });
+  }
+
+  async initMultipartUpload(key, file) {
+    const params = {
+      Bucket: this.bucketname,
+      Key: key,
+      ContentType: file.type,
+      ACL: "public-read"
+    };
+    const data = await this.bucket.createMultipartUpload(params).promise();
+    return data.UploadId;
+  }
+
+  async uploadPart(file, keyname, uploadid, pn, start, end) {
+    if (!this.flag) return;
+    const params = {
+      Bucket: this.bucketname,
+      Key: keyname,
+      PartNumber: pn,
+      UploadId: uploadid,
+      Body: file.slice(start, end)
+    };
+    const result = await this.bucket.uploadPart(params).promise();
+    return { ETag: result.ETag, PartNumber: pn };
+  }
+
+  async completeMultipartUpload(parts, keyname, uploadid) {
+    if (!this.flag) return;
+    const params = {
+      Bucket: this.bucketname,
+      Key: keyname,
+      MultipartUpload: { Parts: parts },
+      UploadId: uploadid
+    };
+    return await this.bucket.completeMultipartUpload(params).promise();
+  }
+
+  async abortMultipartUpload(key, uploadid) {
+    const params = {
+      Bucket: this.bucketname,
+      Key: key,
+      UploadId: uploadid
+    };
+    await this.bucket.abortMultipartUpload(params).promise();
+  }
+
+  async getCheckpoint(key) {
+    let partsinfo;
+    let uploadid = "";
+    try {
+      const result = await this.bucket
+        .listMultipartUploads({ Bucket: this.bucketname, Prefix: key })
+        .promise();
+      if (result.Uploads && result.Uploads.length) {
+        uploadid = result.Uploads[result.Uploads.length - 1].UploadId;
+        partsinfo = await this.bucket
+          .listParts({
+            Bucket: this.bucketname,
+            Key: key,
+            UploadId: uploadid
+          })
+          .promise();
+      }
+    } catch (err) {
+      console.log(err);
+    }
+    return { uploadid, partsinfo };
+  }
+
+  // 控制停止
+  stop() {
+    this.flag = false;
+  }
+
+  emitProgress(filestate, onProgress) {
+    // 只回调变化
+    if (typeof onProgress === "function") {
+      if (
+        !this.lastFilestate ||
+        this.lastFilestate.percent !== filestate.percent ||
+        this.lastFilestate.status !== filestate.status
+      ) {
+        onProgress(Object.assign({}, filestate));
+      }
+    }
+    this.lastFilestate = Object.assign({}, filestate);
+  }
+
+  // 分段上传
+  async uploadParts({ file, uploadid, parts = [], key, onProgress }) {
+    let filestate = { status: "processing", percent: 0 };
+    let partarr = [];
+    const completeparts = parts.map((_) => {
+      partarr.push(_.PartNumber);
+      return { PartNumber: _.PartNumber, ETag: _.ETag };
+    });
+    let len = Math.ceil(file.size / this.partsize);
+
+    if (partarr.length) {
+      filestate.percent = parseInt((completeparts.length * 100) / len);
+      this.emitProgress(filestate, onProgress);
+    }
+
+    for (let i = 0; i < len; i++) {
+      if (!this.flag) break;
+      let start = i * this.partsize;
+      let end = (i + 1) * this.partsize;
+      if (!partarr.includes(i + 1)) {
+        const uploadpart = await this.uploadPart(
+          file,
+          key,
+          uploadid,
+          i + 1,
+          start,
+          end
+        );
+        if (uploadpart && uploadpart.ETag != null) {
+          completeparts.push(uploadpart);
+          partarr.push(uploadpart.PartNumber);
+          filestate.percent = parseInt((completeparts.length * 100) / len);
+          filestate.status = "processing";
+          this.emitProgress(filestate, onProgress);
+        } else {
+          filestate.status = "fail";
+          this.emitProgress(filestate, onProgress);
+          this.stop();
+          throw new Error("分片上传失败");
+        }
+      }
+    }
+    if (this.flag) {
+      const data = await this.completeMultipartUpload(
+        completeparts,
+        key,
+        uploadid
+      );
+      filestate.status = "success";
+      filestate.percent = 100;
+      this.emitProgress(filestate, onProgress);
+      return data; // 返回complete后的aws数据
+    } else {
+      filestate.status = "stop";
+      this.emitProgress(filestate, onProgress);
+      throw new Error("上传已中断");
+    }
+  }
+
+  // 主入口(异步,支持await)
+  /**
+   *
+   * @param {*} param0
+   *  file: 要上传的File对象
+   *  keyName: 指定上传key(可选)
+   *  folderName: 文件夹(可选)
+   *  onProgress: function({status, percent})
+   */
+  async upload({
+    file,
+    keyName,
+    folderName,
+    onProgress
+  }) {
+    if (!file) {
+      throw new Error("请上传文件");
+    }
+    this.flag = true;
+    this.lastFilestate = null;
+    await this.init();
+    let key = "";
+    if (keyName) {
+      key = keyName;
+    } else if (folderName) {
+      key = `${folderName}/${file.name}`;
+    } else {
+      const ext = file.name.split(".").length > 1 ?
+        file.name.substring(file.name.lastIndexOf(".") + 1) : "";
+      key =
+        `${file.name.split(".")[0]}${Date.now()}${ext ? "." + ext : ""}`;
+    }
+    let filestate = { percent: 0, status: "start" };
+    this.emitProgress(filestate, onProgress);
+
+    const params = {
+      Bucket: this.bucketname,
+      Key: key
+    };
+
+    // 用Promise包装, 使upload支持await
+    return new Promise(async (resolve, reject) => {
+      try {
+        // 检查是否已上传
+        this.bucket.headObject(params, async (err, data) => {
+          if (err) {
+            // 检查断点
+            let { uploadid, partsinfo } = await this.getCheckpoint(key);
+            let curUploadId = uploadid;
+            let awsParts = [];
+            if (uploadid && partsinfo) {
+              awsParts = partsinfo.Parts || [];
+            }
+
+            try {
+              let completeResult;
+              if (curUploadId) {
+                completeResult = await this.uploadParts({
+                  file,
+                  uploadid: curUploadId,
+                  parts: awsParts,
+                  key,
+                  onProgress
+                });
+              } else {
+                const newUploadId = await this.initMultipartUpload(key, file);
+                completeResult = await this.uploadParts({
+                  file,
+                  uploadid: newUploadId,
+                  parts: [],
+                  key,
+                  onProgress
+                });
+              }
+              let url = `https://${this.bucketname}.s3.${this.region}.amazonaws.com.cn/${key}`;
+              const resObj = {
+                name: file.name,
+                url: url,
+                size: formatFileSize(file.size),
+                uid: uuidv4(),
+                type: file.type,
+                Key: key,
+                Location: url,
+                ETag: completeResult.ETag,
+                Bucket: this.bucketname
+              };
+              console.log(resObj)
+              resolve(resObj);
+            } catch (err) {
+
+              console.log('分片上传失败', err)
+              reject('');
+            }
+          } else if (data) {
+            // 已经100%
+            let url = `https://${this.bucketname}.s3.${this.region}.amazonaws.com.cn/${key}`;
+            const resObj = {
+              name: file.name,
+              url: url,
+              size: formatFileSize(file.size),
+              uid: uuidv4(),
+              type: file.type,
+              Key: key,
+              Location: url,
+              ETag: data.ETag,
+              Bucket: this.bucketname
+            };
+            filestate.percent = 100;
+            filestate.status = "success";
+            this.emitProgress(filestate, onProgress);
+            resolve(resObj);
+          }
+        });
+      } catch (err) {
+        console.log('分片上传失败', err)
+        reject('');
+      }
+    });
+  }
+}
+
+export {
+  uploadOneFile,
+  getFileType,
+  getFile,
+  getTxtFileContent,
+  AwsMultipartUploader,
+  formatFileSize
+}

+ 15 - 31
src/lang/cn.json

@@ -648,9 +648,9 @@
 
 
 
-  
+
   "data11_5": "11.5",
-  "enterstuname":"请输入学生姓名",  
+  "enterstuname":"请输入学生姓名",
   "enterstuacc":"请输入学生账号",
   "numberstu":"学生数",
   "Cannotsameother":"不能与其他年级名称相同!",
@@ -1048,20 +1048,6 @@
   "ssQChainNotGen":"问题链还未生成完,请前往查看,回答完毕后再次操作。",
   "ssCourseSettings":"课程设置",
   "ssApply":"应用",
-  "ssPublishCourse":"发布课程",
-  "ssVisibilityRange":"可见范围",
-  "ssOnlyStudentsVisible":"仅发布学生可见",
-  "ssOnlyStudentsDesc":"仅对发布的班级学生可见,其他人无法访问",
-  "ssOrganizationVisible":"组织可见",
-  "ssOrganizationDesc":"学校内所有教师均可查看",
-  "ssCourseCover":"课程封面",
-  "ssHoverToSelectUpload":"悬浮选择上传方式",
-  "ssUploadFromLocal":"自本地上传",
-  "ssSearchFromWeb":"自网页搜索",
-  "ssGenerateFromAI":"自AI生成",
-  "ssWebSearchImage":"网页搜索图片",
-  "ssSearchKeyword":"搜索关键词",
-  "ssConfirmPublish":"确认发布",
   "ssTargetNotGen":"目标层还未生成完,请前往查看,回答完毕后再次操作。",
   "ssTaskClusNotGen":"任务簇还未生成完,请前往查看,回答完毕后再次操作。",
   "ssGenDescFirst":"请生成简要描述后再生成大纲",
@@ -2031,19 +2017,17 @@
   "ssNextQ":"下一题",
   "ssUntitledCourse":"暂未命名",
   "ssPPtUpProgress":"上传进度(*)",
-  "ssBilibiliVideoSearchKeyword":"请输入关键词"
-
-
-
-
-
-
-
-
-
-
-
-
-
+  "ssBilibiliVideoSearchKeyword":"请输入关键词",
+  "ssEditGrade":"编辑年级",
+  "ssConfirmDeleteClassStudentone":"确认移除*学生?",
+  "ssExplanationTip":"解释说明",
+  "ssAIGenerate":"AI生成",
+  "ssEnterExplanation":"请输入解释说明",
+  "ssEvaluationStandard":"评价标准",
+  "ssEnterEvaluationStandard":"请输入评价标准",
+  "ssCourseCenter":"课程中心",
+  "ssCourseType":"课程类型",
+  "ssSelectCourseType":"请选择课程类型",
+  "ssSelectedCourse":"已选择 * 个课程"
 
-}
+}

+ 12 - 1
src/lang/en.json

@@ -2030,5 +2030,16 @@
   "ssNextQ":"Next question",
   "ssUntitledCourse":"Untitled Course",
   "ssPPtUpProgress":"Uploading (*)",
-  "ssBilibiliVideoSearchKeyword":"Please enter a keyword"
+  "ssBilibiliVideoSearchKeyword":"Please enter a keyword",
+  "ssEditGrade":"Edit Grade",
+  "ssConfirmDeleteClassStudentone":"Confirm remove * student?",
+  "ssExplanationTip":"Explanation",
+  "ssAIGenerate":"AI Generate",
+  "ssEnterExplanation":"Please enter explanation",
+  "ssEvaluationStandard":"Evaluation Standard",
+  "ssEnterEvaluationStandard":"Please enter evaluation standard",
+  "ssCourseCenter":"Course Center",
+  "ssCourseType":"Course Type",
+  "ssSelectCourseType":"Please select course type",
+  "ssSelectedCourse":"Selected * courses"
 }

+ 38 - 32
src/lang/hk.json

@@ -247,28 +247,28 @@
   "ZhijianCourse": "智見課程",
   "ZhixingCourse": "智行課程",
   "IntelligentCreationCourse": "智創課程",
-  "xiaokeloading": "小可正在努力生成中,請稍等...",  
-  "stop": "停止",  
-  "Fillinbasicinformation": "填寫基本信息",  
-  "Uploadcoursecontent": "上傳課程內容",  
-  "Uploadcompleted": "上傳完成",  
-  "wantintelligent": "是否開啟智能檢索",  
-  "OutputLanguage": "輸出語言",  
-  "SimplifiedChinese": "簡體中文",  
-  "traditionalChinese": "繁體中文",  
-  "English": "English",  
-  "AddCourse": "添加課程",  
-  "Publish": "是否公開此課程",  
-  "SelectLocalImage": "選擇本地文件",  
-  "RefreshResults": "換一組",  
-  "UpdateCover": "修改封面",  
-  "TaskL": "任務*",  
-  "UntitledTask": "未命名任務",  
-  "LearningContent": "學習內容",  
-  "AddLearningContent": "請添加學習內容",  
-  "Files": "文件",  
-  "TextImages": "圖文",  
-  "Links": "鏈接",  
+  "xiaokeloading": "小可正在努力生成中,請稍等...",
+  "stop": "停止",
+  "Fillinbasicinformation": "填寫基本信息",
+  "Uploadcoursecontent": "上傳課程內容",
+  "Uploadcompleted": "上傳完成",
+  "wantintelligent": "是否開啟智能檢索",
+  "OutputLanguage": "輸出語言",
+  "SimplifiedChinese": "簡體中文",
+  "traditionalChinese": "繁體中文",
+  "English": "English",
+  "AddCourse": "添加課程",
+  "Publish": "是否公開此課程",
+  "SelectLocalImage": "選擇本地文件",
+  "RefreshResults": "換一組",
+  "UpdateCover": "修改封面",
+  "TaskL": "任務*",
+  "UntitledTask": "未命名任務",
+  "LearningContent": "學習內容",
+  "AddLearningContent": "請添加學習內容",
+  "Files": "文件",
+  "TextImages": "圖文",
+  "Links": "鏈接",
   "Code": "代碼",
   "TaskOverview": "任務概述",
   "EnterTaskName": "輸入任務名稱",
@@ -647,7 +647,7 @@
   "choosesmartpastemode": "確定選擇智能粘貼模式嗎?",
 
 
-  
+
   "data11_5": "11.5",
   "enterstuname": "請輸入學生姓名",
   "enterstuacc": "請輸入學生賬號",
@@ -686,9 +686,9 @@
   "PPTmode":"互動課件模式",
   "Codeupload": "代碼上傳",
   "StageTitle": "階段標題",
-  
+
   "data11_7": "11.7",
-  
+
   "data11_12": "11.12",
   "joinone": "沒有加入分組請先加入分組",
   "TaskLOverview": "任務*概述",
@@ -2030,12 +2030,18 @@
   "ssNextQ":"下一題",
   "ssUntitledCourse":"暫未命名",
   "ssPPtUpProgress":"上傳進度(*)",
-  "ssBilibiliVideoSearchKeyword":"請輸入關鍵詞"
-
-
-
-
-  
+  "ssBilibiliVideoSearchKeyword":"請輸入關鍵詞",
+  "ssEditGrade":"修改年級",
+  "ssConfirmDeleteClassStudentone":"確定移除 * 名學生嗎?",
+  "ssExplanationTip":"解釋說明",
+  "ssAIGenerate":"AI生成",
+  "ssEnterExplanation":"請輸入解釋說明",
+  "ssEvaluationStandard":"評價標準",
+  "ssEnterEvaluationStandard":"請輸入評價標準",
+  "ssCourseCenter":"課程中心",
+  "ssCourseType":"課程類型",
+  "ssSelectCourseType":"請選擇課程類型",
+  "ssSelectedCourse":"已選擇 * 個課程"
 
 
-}
+}

+ 9 - 0
src/router/index.js

@@ -163,6 +163,7 @@ import Listudent from '@/components/pages/liyuan/page/student'
 import safeTest from '@/components/pages/liyuan/page/safeTest'
 import workPage from '@/components/pages/workPage/index'
 import workPageNew from '@/components/pages/workPage/index_new'
+import setWorkPage from '@/components/pages/workPage/setIndex.vue'
 import pptEasy from '@/components/pages/pptEasy/addCourse'
 import pptEasy2 from '@/components/pages/pptEasy/addCourse2'
 import pptEasy3 from '@/components/pages/pptEasy/addCourse3'
@@ -1494,6 +1495,14 @@ export default new Router({
       requireAuth:''//不需要鉴权
     }
   },
+    {
+      path:"/setWorkPage",
+      name:'setWorkPage',
+      component:setWorkPage,
+      meta:{
+        requireAuth: '',
+      }
+    }
 
 
   ]

+ 9 - 0
src/router/index2.js

@@ -7,6 +7,7 @@ import ElementUI from 'element-ui'
 // 使用路由懒加载,按需加载组件
 import workPage from '@/components/pages/workPage/index'
 import workPageNew from '@/components/pages/workPage/index_new'
+import setWorkPage from '@/components/pages/workPage/setIndex.vue'
 import locale from 'element-ui/lib/locale/lang/en'
 import cn from "../lang/cn.json";
 import hk from "../lang/hk.json";
@@ -58,6 +59,14 @@ export default new Router({
     meta: {
       requireAuth: '' // 是否需要判断是否登录,这里是需要判断
     }
+  },
+  {
+    path:"/setWorkPage",
+    name:'setWorkPage',
+    component:setWorkPage,
+    meta:{
+      requireAuth: '',
+    }
   }
   ]
 })

Неке датотеке нису приказане због велике количине промена