qgt 5 дней назад
Родитель
Сommit
325733e421
39 измененных файлов с 997 добавлено и 104 удалено
  1. 1 1
      dist/index.html
  2. 0 0
      dist/static/css/app.6b7112f2b3d7d6c179183209f430b894.css
  3. 0 0
      dist/static/css/app.6b7112f2b3d7d6c179183209f430b894.css.map
  4. 0 0
      dist/static/js/0.4f3b05586c3acc102a54.js.map
  5. 0 0
      dist/static/js/0.df8814bab917ab2583e0.js
  6. 0 0
      dist/static/js/0.df8814bab917ab2583e0.js.map
  7. 0 0
      dist/static/js/app.d6ee5102f3cdbf0d870d.js
  8. 0 0
      dist/static/js/app.d6ee5102f3cdbf0d870d.js.map
  9. 2 2
      dist/static/js/manifest.9811ebe9d5c4458a1b2a.js
  10. 0 0
      dist/static/js/manifest.9811ebe9d5c4458a1b2a.js.map
  11. 0 0
      dist/static/js/vendor.bb486323f0fa002ba2e7.js
  12. 0 0
      dist/static/js/vendor.bb486323f0fa002ba2e7.js.map
  13. 255 7
      src/components/pages/aiAddCourse/addCourse.vue
  14. 272 4
      src/components/pages/aiEasy/addCourse.vue
  15. 5 3
      src/components/pages/classroomObservation/components/messageArea.vue
  16. 1 1
      src/components/pages/classroomObservation/index.vue
  17. 1 1
      src/components/pages/course.vue
  18. 19 4
      src/components/pages/dialog/selectHtmlPageDialog.vue
  19. 124 47
      src/components/pages/easy/addCourse.vue
  20. 1 1
      src/components/pages/evaluation.vue
  21. 6 5
      src/components/pages/inviteLoginSZ/inviteLogin.vue
  22. 15 2
      src/components/pages/liyuan/CourseCon.vue
  23. 1 1
      src/components/pages/liyuan/aiOffice.vue
  24. 8 2
      src/components/pages/liyuan/components/backPage.vue
  25. 9 2
      src/components/pages/liyuan/components/card.vue
  26. 1 1
      src/components/pages/liyuan/page/examine/index.vue
  27. 1 1
      src/components/pages/liyuan/page/portrait/index.vue
  28. 1 1
      src/components/pages/liyuan/page/student.vue
  29. 264 8
      src/components/pages/newCourse/addCourse.vue
  30. 1 1
      src/components/pages/pptEasy/addCourse.vue
  31. 1 1
      src/components/pages/synergyCourse/course.vue
  32. 1 1
      src/components/pages/sz/teacher.vue
  33. 1 1
      src/components/pages/teacherOffice/index.vue
  34. 1 1
      src/components/pages/test/add/addTest.vue
  35. 1 1
      src/components/pages/test/check/index.vue
  36. 1 1
      src/components/pages/test/examine/index.vue
  37. 1 1
      src/components/pages/test/index.vue
  38. 1 1
      src/components/pages/testStudent/view/preview.vue
  39. 1 1
      src/components/pages/works.vue

+ 1 - 1
dist/index.html

@@ -32,7 +32,7 @@
       width: 100%;
       background: #e6eaf0;
       font-family: '黑体';
-    }</style><link href=./static/css/app.7f0350c7c58c94a91dc72a67e1a9d06e.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.161e82026ac2ae03ab6f.js></script><script type=text/javascript src=./static/js/vendor.b7212920b6e58d14a873.js></script><script type=text/javascript src=./static/js/app.348ba96eadb546c2a650.js></script></body></html><script>function stopSafari() {
+    }</style><link href=./static/css/app.6b7112f2b3d7d6c179183209f430b894.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.9811ebe9d5c4458a1b2a.js></script><script type=text/javascript src=./static/js/vendor.bb486323f0fa002ba2e7.js></script><script type=text/javascript src=./static/js/app.d6ee5102f3cdbf0d870d.js></script></body></html><script>function stopSafari() {
     //阻止safari浏览器双击放大功能
     let lastTouchEnd = 0  //更新手指弹起的时间
     document.documentElement.addEventListener("touchstart", function (event) {

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/css/app.6b7112f2b3d7d6c179183209f430b894.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/css/app.6b7112f2b3d7d6c179183209f430b894.css.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/0.4f3b05586c3acc102a54.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/0.df8814bab917ab2583e0.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/0.df8814bab917ab2583e0.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/app.d6ee5102f3cdbf0d870d.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/app.d6ee5102f3cdbf0d870d.js.map


+ 2 - 2
dist/static/js/manifest.161e82026ac2ae03ab6f.js → dist/static/js/manifest.9811ebe9d5c4458a1b2a.js

@@ -1,2 +1,2 @@
-!function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,c,a){for(var i,u,f,s=0,l=[];s<r.length;s++)u=r[s],t[u]&&l.push(t[u][0]),t[u]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(n&&n(r,c,a);l.length;)l.shift()();if(a)for(s=0;s<a.length;s++)f=o(o.s=a[s]);return f};var r={},t={6:0};function o(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.e=function(e){var n=t[e];if(0===n)return new Promise(function(e){e()});if(n)return n[2];var r=new Promise(function(r,o){n=t[e]=[r,o]});n[2]=r;var c=document.getElementsByTagName("head")[0],a=document.createElement("script");a.type="text/javascript",a.charset="utf-8",a.async=!0,a.timeout=12e4,o.nc&&a.setAttribute("nonce",o.nc),a.src=o.p+"static/js/"+e+"."+{0:"4f3b05586c3acc102a54",1:"14e8e8c7e44fc858e4a6",2:"94e1427bfc7ef0b4c685",3:"3a9f53a78da16650e6b8"}[e]+".js";var i=setTimeout(u,12e4);function u(){a.onerror=a.onload=null,clearTimeout(i);var n=t[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),t[e]=void 0)}return a.onerror=a.onload=u,c.appendChild(a),r},o.m=e,o.c=r,o.d=function(e,n,r){o.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="./",o.oe=function(e){throw console.error(e),e}}([]);
-//# sourceMappingURL=manifest.161e82026ac2ae03ab6f.js.map
+!function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,a,c){for(var i,u,f,s=0,l=[];s<r.length;s++)u=r[s],t[u]&&l.push(t[u][0]),t[u]=0;for(i in a)Object.prototype.hasOwnProperty.call(a,i)&&(e[i]=a[i]);for(n&&n(r,a,c);l.length;)l.shift()();if(c)for(s=0;s<c.length;s++)f=o(o.s=c[s]);return f};var r={},t={6:0};function o(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.e=function(e){var n=t[e];if(0===n)return new Promise(function(e){e()});if(n)return n[2];var r=new Promise(function(r,o){n=t[e]=[r,o]});n[2]=r;var a=document.getElementsByTagName("head")[0],c=document.createElement("script");c.type="text/javascript",c.charset="utf-8",c.async=!0,c.timeout=12e4,o.nc&&c.setAttribute("nonce",o.nc),c.src=o.p+"static/js/"+e+"."+{0:"df8814bab917ab2583e0",1:"14e8e8c7e44fc858e4a6",2:"94e1427bfc7ef0b4c685",3:"3a9f53a78da16650e6b8"}[e]+".js";var i=setTimeout(u,12e4);function u(){c.onerror=c.onload=null,clearTimeout(i);var n=t[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),t[e]=void 0)}return c.onerror=c.onload=u,a.appendChild(c),r},o.m=e,o.c=r,o.d=function(e,n,r){o.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="./",o.oe=function(e){throw console.error(e),e}}([]);
+//# sourceMappingURL=manifest.9811ebe9d5c4458a1b2a.js.map

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/manifest.9811ebe9d5c4458a1b2a.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/vendor.bb486323f0fa002ba2e7.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/vendor.bb486323f0fa002ba2e7.js.map


+ 255 - 7
src/components/pages/aiAddCourse/addCourse.vue

@@ -3455,6 +3455,11 @@
                                     class="chapter_upload_l_i15"
                                     style="margin-left: 1px"
                                   ></div>
+                                  <div
+                                    v-if="item1.type == 17"
+                                    class="chapter_upload_l_i8"
+                                    style="margin-left: 1px"
+                                  ></div>
                                   </div>
                                   <div class="chapter_upload_n">
                                     <input
@@ -3522,6 +3527,22 @@
                                         overflow: hidden;
                                         text-overflow: ellipsis;
                                       " readonly="true" @click="selectLine(itemTaskIndex, index1)" />
+                                     <input
+                                    :placeholder="
+                                      item1.title ? item1.title : '代码上传'
+                                    "
+                                    v-if="item1.type == 17"
+                                    style="
+                                  border: none;
+                                  outline: none;
+                                  width: 80%;
+                                  white-space: nowrap;
+                                  overflow: hidden;
+                                  text-overflow: ellipsis;
+                                "
+                                    readonly="true"
+                                    @click="changeHTmlPage(itemTaskIndex, index1)"
+                                  />
                                     <input :placeholder="
                                         item1.title ? item1.title : '链接'
                                       " v-if="item1.type == 14" style="
@@ -3614,6 +3635,13 @@
                                       @click="selectLine(itemTaskIndex, index1)">
                                       <div></div>
                                     </div>
+                                    <div
+                                    class="chapter_upload_ic_edit"
+                                    v-if="item1.type == 17"
+                                    @click="changeHTmlPage(itemTaskIndex, index1)"
+                                  >
+                                    <div></div>
+                                  </div>
                                     <div class="chapter_upload_ic_edit" v-if="item1.type == 14" @click="
                                         openUpdateSource(itemTaskIndex, index1)
                                       ">
@@ -3689,6 +3717,13 @@
                           >
                             代码编辑器
                           </button>
+
+                          <button
+                            class="c_pub_button_add pub_btn_add_img"
+                                @click="uploadZIPFile(itemTaskIndex)"
+                          >
+                            代码上传
+                          </button>
                           </div>
                           <div v-if="
                               unitJson[unitIndex].chapterInfo[0].taskJson[
@@ -3808,6 +3843,11 @@
                                     class="chapter_upload_l_i15"
                                     style="margin-left: 1px"
                                   ></div>
+                                  <div
+                                    v-if="item1.type == 17"
+                                    class="chapter_upload_l_i8"
+                                    style="margin-left: 1px"
+                                  ></div>
                                   </div>
                                   <div class="chapter_upload_n">
                                     <span style="
@@ -3862,6 +3902,22 @@
                                         text-overflow: ellipsis;
                                       " readonly="true" @click="selectLine(itemTaskIndex, index1)" />
                                       <input
+                                    :placeholder="
+                                      item1.title ? item1.title : '代码上传'
+                                    "
+                                    v-if="item1.type == 17"
+                                    style="
+                                  border: none;
+                                  outline: none;
+                                  width: 80%;
+                                  white-space: nowrap;
+                                  overflow: hidden;
+                                  text-overflow: ellipsis;
+                                "
+                                    readonly="true"
+                                    @click="changeHTmlPage(itemTaskIndex, index1)"
+                                  />
+                                      <input
                                     :placeholder="
                                       item1.title ? item1.title : 'Ai应用'
                                     "
@@ -7634,7 +7690,7 @@
     <wOffice :dialogVisibleOffice.sync="dialogVisibleOffice" :url="wurl"></wOffice>
     <appDialog ref="appDialog" @success="selectAppSuccess"></appDialog>
     <CodeEditor ref="CodeEditorRef" @success="addHtmlSuccess"></CodeEditor>
-
+    <selectHtmlPageDialog ref="selectHtmlPageDialogRef" @success="selectHtmlPageSuccess"/>
   </div>
 </template>
 
@@ -7678,6 +7734,7 @@ let convertApi = ConvertApi.auth('secret_U1EO5rhgMCnoBnBT')
 import appDialog from '../components/appDialog.vue'
 import { myMixin } from "@/mixins/mixin.js"
 import CodeEditor from "../components/CodeEditor";
+import { uploadFileMixin } from "../../tools/uploadFileMixin.js";
 
 var OpenCC = require("opencc-js");
 let converter = OpenCC.Converter({
@@ -7689,6 +7746,7 @@ let converter2 = OpenCC.Converter({
 		from:'cn',
 		to:'hk'
 })
+import selectHtmlPageDialog from '../dialog/selectHtmlPageDialog.vue'
 
 const getFile = (url) => {
   return new Promise((resolve, reject) => {
@@ -7729,7 +7787,7 @@ const getFile = (url) => {
 };
 
 export default {
-  mixins: [ myMixin ],
+  mixins: [ myMixin,uploadFileMixin ],
   components: {
     CodeEditor,
     EditorBar,
@@ -7756,11 +7814,12 @@ export default {
     evaList,
     MindTask,
     recordV,
-    appDialog
+    appDialog,
+    selectHtmlPageDialog
   },
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype: (window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       checkAll: false,
       checkAll2: false,
       chooseType: 1,
@@ -8268,8 +8327,8 @@ export default {
       knowFileType: "",
       knowFileTypeArray1: ['上册', '下册'],
       knowFileTypeArray: ['作业', '教案', '其他'],
-      optionTypeList:['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
-
+      optionTypeList:['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'],
+      changeId:"",
     };
   },
   directives: {
@@ -26216,7 +26275,196 @@ ${msg}
       }
       this.imgChange1(null, null, 8, this.lineCount);
       this.dialogVisible7 = false;
-    }
+    },
+    // zip压缩文件上传
+    uploadZIPFile(i){
+      this.lineCount = i;
+      // 只支持上传zip文件
+      let input = document.createElement('input');
+      input.type = 'file';
+      input.accept = '.zip';
+      input.style.display = 'none';
+      // 只允许上传一个文件
+      input.multiple = false;
+      input.onchange = async (e) => {
+        let file = e.target.files[0];
+        if (!file) return;
+        if (file.type !== 'application/zip' && !file.name.endsWith('.zip')) {
+          this.$message.error('只支持上传zip文件');
+          return;
+        }
+        try{
+          const zip = new JSZip();
+          const content = await zip.loadAsync(file);
+          let _fileStructure = this.buildFileStructure(file,content);
+          let _time = new Date().getTime();
+          let _resultList = await this.uploadZipFileFn(_fileStructure.files,`${_time}_${_fileStructure.folderName}`);
+          this.changeId = "";
+          this.$refs.selectHtmlPageDialogRef.open(_resultList);
+        
+        }catch(e){
+          console.log(e)
+          this.$message.error("解析zip文件失败")
+        }
+      
+      };
+      document.body.appendChild(input);
+      input.click();
+      setTimeout(() => {
+        document.body.removeChild(input);
+      }, 1000);
+      },
+      // 构建文件结构树
+      buildFileStructure(file,zip) {
+      const root = {
+        folderName: file.name.replace(/\.[^/.]+$/, ""), // 移除扩展名
+        files: []
+      };
+      
+      // 遍历ZIP文件中的所有文件/文件夹
+      zip.forEach((relativePath, file) => {
+        if (file.dir) return; // 跳过目录
+      
+        const parts = relativePath.split('/');
+        let currentLevel = root.files;
+      
+        for (let i = 0; i < parts.length; i++) {
+          const part = parts[i];
+          const isLast = i === parts.length - 1;
+        
+          if (isLast) {
+            // 添加文件
+            currentLevel.push({fileName:part,file:file});
+          } else {
+            // 查找或创建文件夹
+            let folder = currentLevel.find(item =>
+              typeof item === 'object' && item.folderName === part
+            );
+          
+            if (!folder) {
+              folder = {
+                folderName: part,
+                files: []
+              };
+              currentLevel.push(folder);
+            }
+          
+            currentLevel = folder.files;
+          }
+        }
+      });
+      
+      return root;
+      },
+      //按路径上传文件
+      async uploadZipFileFn(fileList,path){
+      return new Promise(async (resolve)=>{
+        let _copyFileList = fileList;
+      
+        let promise = [];
+        for(let i = 0; i < _copyFileList.length; i++){
+          if(_copyFileList[i].folderName){
+            let _path = `${path}/${_copyFileList[i].folderName}`;
+            promise.push(this.uploadZipFileFn(_copyFileList[i].files,_path).then(res=>{
+              _copyFileList[i].files = res;
+            }))
+          }else if(_copyFileList[i].fileName){
+            // 将 ZIP 条目转换为文件对象
+            const blob = await _copyFileList[i].file.async('blob');
+            // 根据文件名设置type
+            let type = 'text/html';
+            if (_copyFileList[i].fileName.endsWith('.js')) {
+              type = 'application/javascript';
+            } else if (_copyFileList[i].fileName.endsWith('.css')) {
+              type = 'text/css';
+            } else if (_copyFileList[i].fileName.endsWith('.json')) {
+              type = 'application/json';
+            } else if (_copyFileList[i].fileName.endsWith('.png')) {
+              type = 'image/png';
+            } else if (_copyFileList[i].fileName.endsWith('.jpg') || _copyFileList[i].fileName.endsWith('.jpeg')) {
+              type = 'image/jpeg';
+            } else if (_copyFileList[i].fileName.endsWith('.gif')) {
+              type = 'image/gif';
+            } else if (_copyFileList[i].fileName.endsWith('.svg')) {
+              type = 'image/svg+xml';
+            } else if (_copyFileList[i].fileName.endsWith('.html') || _copyFileList[i].fileName.endsWith('.htm')) {
+              type = 'text/html';
+            } else if (_copyFileList[i].fileName.endsWith('.txt')) {
+              type = 'text/plain';
+            } else if (_copyFileList[i].fileName.endsWith('.pdf')) {
+              type = 'application/pdf';
+            } else if (_copyFileList[i].fileName.endsWith('.mp3')) {
+              type = 'audio/mpeg';
+            } else if (_copyFileList[i].fileName.endsWith('.mp4')) {
+              type = 'video/mp4';
+            } else if (_copyFileList[i].fileName.endsWith('.zip')) {
+              type = 'application/zip';
+            } else if (_copyFileList[i].fileName.endsWith('.xml')) {
+              type = 'application/xml';
+            } else if (_copyFileList[i].fileName.endsWith('.csv')) {
+              type = 'text/csv';
+            } else if (_copyFileList[i].fileName.endsWith('.md')) {
+              type = 'text/markdown';
+            }
+            let _file = new File([blob], _copyFileList[i].fileName, {type: type, lastModified: new Date().getTime()});
+            promise.push(this.awsupload({file:_file,path:`${path}/${_copyFileList[i].fileName}`}).then(res=>{
+              delete _copyFileList[i].file;
+              _copyFileList[i].url = decodeURIComponent(res.Location);
+            }))
+          }
+        }
+        Promise.all(promise).then(res=>{
+          resolve(_copyFileList);
+        })
+      })
+      },
+      selectHtmlPageSuccess(data){
+      let _selectFile = data.find(i=>i.isSelect==="1");
+      if(!_selectFile){
+        this.changeId = "";
+        return this.$message.info("未选择主页面")
+      }
+      
+      console.log("_selectFile",_selectFile)
+      let _index = this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+      this.lineCount
+      ].chapterData.findIndex(i => i.type == 17 && i.id == this.changeId);
+      if (_index != -1) {
+        console.log("_index",_index)
+        this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+          this.lineCount
+        ].chapterData[_index] = {
+          name: _selectFile.fileName,
+          title: _selectFile.fileName,
+          id:this.changeId,
+          url: _selectFile.url,
+          fileList:data,
+          type: 17
+        };
+      } else {
+        this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+        this.lineCount
+        ].chapterData.push({
+          name: _selectFile.fileName,
+          title: _selectFile.fileName,
+          id:new Date().getTime(),
+          url: _selectFile.url,
+          fileList:data,
+          type: 17
+        });
+      }
+      this.changeId = "";
+      this.$forceUpdate();
+      this.$refs.selectHtmlPageDialogRef.close();
+      },
+      changeHTmlPage(itemTaskIndex,i){
+        let _data = this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+          itemTaskIndex
+        ].chapterData[i];
+        this.lineCount = itemTaskIndex;
+        this.changeId = _data.id;
+        this.$refs.selectHtmlPageDialogRef.open(_data.fileList);
+      }
   },
   beforeDestroy() {
     // clearTimeout(this.timer);

+ 272 - 4
src/components/pages/aiEasy/addCourse.vue

@@ -471,6 +471,11 @@
 
                                 <div v-if="item1.type == 15" class="chapter_upload_l_i15" style="margin-left: 1px">
                                 </div>
+                                <div
+                                    v-if="item1.type == 17"
+                                    class="chapter_upload_l_i8"
+                                    style="margin-left: 1px"
+                                  ></div>
                               </div>
                               <div class="chapter_upload_n" :class="{dataTips: !item1.fileid}">
 
@@ -498,6 +503,9 @@
                                 <div v-if="item1.type == 14" class="chapter_upload_box" @click="
                                         openUpdateSource(0, index1)
                                         " >{{ item1.title ? item1.title : '链接' }}</div>
+                                <div v-if="item1.type == 17" class="chapter_upload_box" @click="
+                                        changeHTmlPage(0, index1)
+                                        " >{{ item1.title ? item1.title : '代码上传' }}</div>
                                    <div v-if="item1.type == 15" class="chapter_upload_box" @click="
                                         openUpdateSource(0, index1)
                                         " >{{ item1.title ? item1.title : 'Ai应用' }}</div>
@@ -564,6 +572,13 @@
                                   ">
                                   <div></div>
                                 </div>
+                                <div
+                                    class="chapter_upload_ic_edit"
+                                    v-if="item1.type == 17"
+                                    @click="changeHTmlPage(0, index1)"
+                                  >
+                                    <div></div>
+                                  </div>
                                 <div class="chapter_upload_ic_r" @click.stop="
                                   deleteChapterData(
                                     $event,
@@ -625,6 +640,12 @@
                         >
                           代码编辑器
                         </button>
+                        <button
+                            class="c_pub_button_add pub_btn_add_img"
+                                @click="uploadZIPFile(0)"
+                          >
+                            代码上传
+                          </button>
                       </div>
                       <div v-if="
                         unitJson[unitIndex].chapterInfo[0].taskJson[
@@ -1118,6 +1139,22 @@
                                         overflow: hidden;
                                         text-overflow: ellipsis;
                                       " readonly="true" @click="selectLine(index1)" />
+                          <input
+                                    :placeholder="
+                                      item1.title ? item1.title : '代码上传'
+                                    "
+                                    v-if="item1.type == 17"
+                                    style="
+                                  border: none;
+                                  outline: none;
+                                  width: 80%;
+                                  white-space: nowrap;
+                                  overflow: hidden;
+                                  text-overflow: ellipsis;
+                                "
+                                    readonly="true"
+                                    @click="changeHTmlPage(0, index1)"
+                                  />
                           <input :placeholder="item1.title ? item1.title : '链接'
                             " v-if="item1.type == 14" style="
                                         border: none;
@@ -2964,6 +3001,11 @@
                                     class="chapter_upload_l_i15"
                                     style="margin-left: 1px"
                                   ></div>
+                                  <div
+                                    v-if="item1.type == 17"
+                                    class="chapter_upload_l_i8"
+                                    style="margin-left: 1px"
+                                  ></div>
                                   </div>
                                   <div class="chapter_upload_n">
                                     <input
@@ -3062,6 +3104,23 @@
                                     readonly="true"
                                     @click="selectLine(0, index1)"
                                   />
+                                  <input
+                                    :placeholder="
+                                      item1.title ? item1.title : '代码上传'
+                                    "
+                                    v-if="item1.type == 17"
+                                    style="
+                                  border: none;
+                                  outline: none;
+                                  width: 80%;
+                                  white-space: nowrap;
+                                  overflow: hidden;
+                                  text-overflow: ellipsis;
+                                "
+                                    readonly="true"
+                                    @click="changeHTmlPage(0, index1)"
+                                  />
+
                                   </div>
                                   <div class="chapter_upload_ic">
                                     <div
@@ -3147,6 +3206,13 @@
                                     >
                                       <div></div>
                                     </div>
+                                    <div
+                                    class="chapter_upload_ic_edit"
+                                    v-if="item1.type == 17"
+                                    @click="changeHTmlPage(0, index1)"
+                                  >
+                                    <div></div>
+                                  </div>
                                     <div
                                       class="chapter_upload_ic_r"
                                       @click.stop="
@@ -3460,6 +3526,13 @@
                                       ">
                                       <div></div>
                                     </div>
+                                    <div
+                                    class="chapter_upload_ic_edit"
+                                    v-if="item1.type == 17"
+                                    @click="changeHTmlPage(0, index1)"
+                                  >
+                                    <div></div>
+                                  </div>
                                     <div class="chapter_upload_ic_r" @click.stop="
                                       deleteChapterData(
                                         $event,
@@ -7057,6 +7130,7 @@
     <wOffice :dialogVisibleOffice.sync="dialogVisibleOffice" :url="wurl" ></wOffice>
     <appDialog ref="appDialog" @success="selectAppSuccess"></appDialog>
     <CodeEditor ref="CodeEditorRef" @success="addHtmlSuccess"></CodeEditor>
+    <selectHtmlPageDialog ref="selectHtmlPageDialogRef" @success="selectHtmlPageSuccess"/>
   </div>
 </template>
 
@@ -7100,6 +7174,7 @@ let convertApi = ConvertApi.auth('secret_U1EO5rhgMCnoBnBT')
 import appDialog from '../components/appDialog.vue'
 import { myMixin } from "@/mixins/mixin.js"
 import CodeEditor from "../components/CodeEditor";
+import { uploadFileMixin } from "../../tools/uploadFileMixin.js";
 
 var OpenCC = require("opencc-js");
 let converter = OpenCC.Converter({
@@ -7112,6 +7187,9 @@ let converter2 = OpenCC.Converter({
 		to:'hk'
 })
 
+
+import selectHtmlPageDialog from '../dialog/selectHtmlPageDialog.vue'
+
 const getFile = (url) => {
   return new Promise((resolve, reject) => {
     var credentials = {
@@ -7151,7 +7229,7 @@ const getFile = (url) => {
 };
 
 export default {
-  mixins: [ myMixin ],
+  mixins: [ myMixin,uploadFileMixin],
   components: {
     CodeEditor,
     EditorBar,
@@ -7179,10 +7257,11 @@ export default {
     MindTask,
     recordV,
     appDialog,
+    selectHtmlPageDialog
   },
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype: (window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       checkAll: false,
       checkAll2: false,
       chooseType: 1,
@@ -7658,7 +7737,8 @@ export default {
       heightPx: '100%',
       newWidth: 350,
       unitLoading: false,
-      optionTypeList:['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
+      optionTypeList:['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'],
+      changeId:""
 
     };
   },
@@ -25527,7 +25607,195 @@ ${msg}
       }
       this.imgChange1(null, null, 8, this.lineCount);
       this.dialogVisible7 = false;
-    }
+    },
+    // zip压缩文件上传
+    uploadZIPFile(i){
+        this.lineCount = i;
+        // 只支持上传zip文件
+        let input = document.createElement('input');
+        input.type = 'file';
+        input.accept = '.zip';
+        input.style.display = 'none';
+        // 只允许上传一个文件
+        input.multiple = false;
+        input.onchange = async (e) => {
+          let file = e.target.files[0];
+          if (!file) return;
+          if (file.type !== 'application/zip' && !file.name.endsWith('.zip')) {
+            this.$message.error('只支持上传zip文件');
+            return;
+          }
+          try{
+            const zip = new JSZip();
+            const content = await zip.loadAsync(file);
+            let _fileStructure = this.buildFileStructure(file,content);
+            let _time = new Date().getTime();
+            let _resultList = await this.uploadZipFileFn(_fileStructure.files,`${_time}_${_fileStructure.folderName}`);
+            this.changeId = "";
+            this.$refs.selectHtmlPageDialogRef.open(_resultList);
+          
+          }catch(e){
+            console.log(e)
+            this.$message.error("解析zip文件失败")
+          }
+        
+        };
+        document.body.appendChild(input);
+        input.click();
+        setTimeout(() => {
+          document.body.removeChild(input);
+        }, 1000);
+        },
+        // 构建文件结构树
+        buildFileStructure(file,zip) {
+        const root = {
+          folderName: file.name.replace(/\.[^/.]+$/, ""), // 移除扩展名
+          files: []
+        };
+
+        // 遍历ZIP文件中的所有文件/文件夹
+        zip.forEach((relativePath, file) => {
+          if (file.dir) return; // 跳过目录
+        
+          const parts = relativePath.split('/');
+          let currentLevel = root.files;
+        
+          for (let i = 0; i < parts.length; i++) {
+            const part = parts[i];
+            const isLast = i === parts.length - 1;
+          
+            if (isLast) {
+              // 添加文件
+              currentLevel.push({fileName:part,file:file});
+            } else {
+              // 查找或创建文件夹
+              let folder = currentLevel.find(item =>
+                typeof item === 'object' && item.folderName === part
+              );
+            
+              if (!folder) {
+                folder = {
+                  folderName: part,
+                  files: []
+                };
+                currentLevel.push(folder);
+              }
+            
+              currentLevel = folder.files;
+            }
+          }
+        });
+
+        return root;
+        },
+        //按路径上传文件
+        async uploadZipFileFn(fileList,path){
+        return new Promise(async (resolve)=>{
+          let _copyFileList = fileList;
+        
+          let promise = [];
+          for(let i = 0; i < _copyFileList.length; i++){
+            if(_copyFileList[i].folderName){
+              let _path = `${path}/${_copyFileList[i].folderName}`;
+              promise.push(this.uploadZipFileFn(_copyFileList[i].files,_path).then(res=>{
+                _copyFileList[i].files = res;
+              }))
+            }else if(_copyFileList[i].fileName){
+              // 将 ZIP 条目转换为文件对象
+              const blob = await _copyFileList[i].file.async('blob');
+              // 根据文件名设置type
+              let type = 'text/html';
+              if (_copyFileList[i].fileName.endsWith('.js')) {
+                type = 'application/javascript';
+              } else if (_copyFileList[i].fileName.endsWith('.css')) {
+                type = 'text/css';
+              } else if (_copyFileList[i].fileName.endsWith('.json')) {
+                type = 'application/json';
+              } else if (_copyFileList[i].fileName.endsWith('.png')) {
+                type = 'image/png';
+              } else if (_copyFileList[i].fileName.endsWith('.jpg') || _copyFileList[i].fileName.endsWith('.jpeg')) {
+                type = 'image/jpeg';
+              } else if (_copyFileList[i].fileName.endsWith('.gif')) {
+                type = 'image/gif';
+              } else if (_copyFileList[i].fileName.endsWith('.svg')) {
+                type = 'image/svg+xml';
+              } else if (_copyFileList[i].fileName.endsWith('.html') || _copyFileList[i].fileName.endsWith('.htm')) {
+                type = 'text/html';
+              } else if (_copyFileList[i].fileName.endsWith('.txt')) {
+                type = 'text/plain';
+              } else if (_copyFileList[i].fileName.endsWith('.pdf')) {
+                type = 'application/pdf';
+              } else if (_copyFileList[i].fileName.endsWith('.mp3')) {
+                type = 'audio/mpeg';
+              } else if (_copyFileList[i].fileName.endsWith('.mp4')) {
+                type = 'video/mp4';
+              } else if (_copyFileList[i].fileName.endsWith('.zip')) {
+                type = 'application/zip';
+              } else if (_copyFileList[i].fileName.endsWith('.xml')) {
+                type = 'application/xml';
+              } else if (_copyFileList[i].fileName.endsWith('.csv')) {
+                type = 'text/csv';
+              } else if (_copyFileList[i].fileName.endsWith('.md')) {
+                type = 'text/markdown';
+              }
+              let _file = new File([blob], _copyFileList[i].fileName, {type: type, lastModified: new Date().getTime()});
+              promise.push(this.awsupload({file:_file,path:`${path}/${_copyFileList[i].fileName}`}).then(res=>{
+                delete _copyFileList[i].file;
+                _copyFileList[i].url = decodeURIComponent(res.Location);
+              }))
+            }
+          }
+          Promise.all(promise).then(res=>{
+            resolve(_copyFileList);
+          })
+        })
+        },
+        selectHtmlPageSuccess(data){
+        let _selectFile = data.find(i=>i.isSelect==="1");
+        if(!_selectFile){
+          this.changeId = "";
+          return this.$message.info("未选择主页面")
+        }
+
+        console.log("_selectFile",_selectFile)
+        let _index = this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+          0
+        ].chapterData.findIndex(i => i.type == 17 && i.id == this.changeId);
+        if (_index != -1) {
+          console.log("_index",_index)
+          this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+            0
+          ].chapterData[_index] = {
+            name: _selectFile.fileName,
+            title: _selectFile.fileName,
+            id:this.changeId,
+            url: _selectFile.url,
+            fileList:data,
+            type: 17
+          };
+        } else {
+          this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+            0
+          ].chapterData.push({
+            name: _selectFile.fileName,
+            title: _selectFile.fileName,
+            id:new Date().getTime(),
+            url: _selectFile.url,
+            fileList:data,
+            type: 17
+          });
+        }
+        this.changeId = "";
+        this.$forceUpdate();
+        this.$refs.selectHtmlPageDialogRef.close();
+        },
+        changeHTmlPage(itemTaskIndex,i){
+        let _data = this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+          itemTaskIndex
+        ].chapterData[i];
+        this.changeId = _data.id;
+        this.$refs.selectHtmlPageDialogRef.open(_data.fileList);
+        }
   },
   beforeDestroy() {
     // clearTimeout(this.timer);

+ 5 - 3
src/components/pages/classroomObservation/components/messageArea.vue

@@ -279,8 +279,8 @@ export default {
 			return new Promise(resolve => {
 				if(this.bmData && this.bmData.jsonData && this.bmData.jsonData.editorBarData){
 					if(this.bmData.jsonData.editorBarData && (this.bmData.jsonData.editorBarData.content || this.bmData.jsonData.editorBarData.url)){
-						this.$confirm("是否保留本课堂的转录文稿数据至新课堂?","提示").then(_ => {
-							window.localStorage.setItem("saveEditorBarData",JSON.stringify({editorBarData:this.bmData.jsonData.editorBarData,fileId:this.fileId}));
+						this.$confirm("是否复用当前数据?","提示").then(_ => {
+							window.localStorage.setItem("saveEditorBarData",JSON.stringify({fileId:this.fileId,bmData:this.bmData.jsonData,imageList:this.imageList.jsonData}));
 							resolve(1);
 						}).catch(_ => {
 							resolve(2);
@@ -675,7 +675,8 @@ export default {
 							let saveEditorBarData = window.localStorage.getItem("saveEditorBarData")?JSON.parse(window.localStorage.getItem("saveEditorBarData")):null;
 							if(saveEditorBarData){
 								console.log("saveEditorBarData👉",saveEditorBarData)
-								_bmData.jsonData.editorBarData = saveEditorBarData.editorBarData;
+								_bmData.jsonData = saveEditorBarData.bmData;
+                _imageList.jsonData = saveEditorBarData.imageList;
 								// this.fileId = _saveEditorBarData.fileId;
 								window.localStorage.removeItem("saveEditorBarData");
 							}
@@ -711,6 +712,7 @@ export default {
 								console.log("保存数据👉",saveEditorBarData)
 								this.$parent.updateFileId(saveEditorBarData.fileId);
 								this.saveData(this.bmData);
+                this.saveData(this.imageList)
 							}
               resolve();
             } else {

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

@@ -264,7 +264,7 @@ export default {
   },
   data() {
     return {
-      gotype: sessionStorage.getItem("gotype"),
+      gotype: (window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       loading: false,
       createTime: new Date().toLocaleString().replaceAll("/", "-"),
       tid: "",

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

@@ -443,7 +443,7 @@ export default {
   mixins: [ myMixin ],
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       itemCount: 1,
       courseTitle: "",
       courseText: "",

+ 19 - 4
src/components/pages/dialog/selectHtmlPageDialog.vue

@@ -3,7 +3,6 @@
 		<el-dialog
 			:center="true"
 			:visible.sync="show"
-			:close-on-click-modal="true"
 			:modal="true"
 			width="auto"
 			height="auto"
@@ -47,8 +46,8 @@
             <el-table-column label="文件名称" align="center" prop="fileName" />
             <el-table-column label="操作" width="200" align="center">
               <template slot-scope="scope">
-                <el-button type="primary" v-if="!scope.row.isSelect" size="small" @click="select(scope.row)">选择</el-button>
-                <el-button v-if="scope.row.isSelect" size="small" @click="close()">已选</el-button>
+                <el-button type="primary" v-if="scope.row.isSelect!='1'" size="small" @click="select(scope.row)">选择</el-button>
+                <el-button v-if="scope.row.isSelect=='1'" size="small" @click="close()">已选</el-button>
               </template>
             </el-table-column>
           </el-table>
@@ -71,6 +70,18 @@ export default {
 	methods: {
 		open(data) {
 			this.data = JSON.parse(JSON.stringify(data));
+      let _levelOne = JSON.parse(JSON.stringify(this.data.filter(i=>i.fileName)));
+			// 筛选url为html文件的项
+			this.tableData = _levelOne.filter(item => {
+				return item.url && (item.url.endsWith('.html') || item.url.endsWith('.htm'));
+			});
+
+      if(this.tableData.length<=0){
+        this.$message.error("一级文件夹下未查询到页面文件")
+        return this.close()
+      }
+
+
 			this.loading = false;
 			this.show = true;
 		},
@@ -81,12 +92,16 @@ export default {
 		init() {
 			this.data = null;
 			this.loading = false;
+      this.tableData = [];
 		},
     submit(){
       this.$message.info("选择确定")
     },
     select(row){
-      console.log("选择",row)
+      this.data.forEach(i=>{if(i.isSelect)delete i.isSelect})
+      this.data.find(i=>i.url===row.url).isSelect = "1";
+      console.log("选择data",this.data)
+      this.$emit("success",this.data)
     },
 	},
 };

+ 124 - 47
src/components/pages/easy/addCourse.vue

@@ -516,6 +516,12 @@
                                     class="chapter_upload_l_i15"
                                     style="margin-left: 1px"
                                   ></div>
+
+                                  <div
+                                    v-if="item1.type == 17"
+                                    class="chapter_upload_l_i8"
+                                    style="margin-left: 1px"
+                                  ></div>
                                 </div>
                                 <div class="chapter_upload_n">
                                   <input
@@ -628,6 +634,23 @@
                                     readonly="true"
                                     @click="openUpdateSource(0, index1)"
                                   />
+
+                                  <input
+                                    :placeholder="
+                                      item1.title ? item1.title : '代码上传'
+                                    "
+                                    v-if="item1.type == 17"
+                                    style="
+                                  border: none;
+                                  outline: none;
+                                  width: 80%;
+                                  white-space: nowrap;
+                                  overflow: hidden;
+                                  text-overflow: ellipsis;
+                                "
+                                    readonly="true"
+                                    @click="changeHTmlPage(0, index1)"
+                                  />
                                 </div>
                                 <div class="chapter_upload_ic">
                                   <div
@@ -703,6 +726,14 @@
                                   >
                                     <div></div>
                                   </div>
+
+                                  <div
+                                    class="chapter_upload_ic_edit"
+                                    v-if="item1.type == 17"
+                                    @click="changeHTmlPage(0, index1)"
+                                  >
+                                    <div></div>
+                                  </div>
                                   <div
                                     class="chapter_upload_ic_edit"
                                     v-if="item1.type == 14"
@@ -786,12 +817,12 @@
                               <input type="file" accept="*" style="display: none" v-if="inputShow" @change="beforeUpload2($event, unitIndex, 12, itemTaskIndex)
                                 " />
                             </button> -->
-                            <!-- <button
+                            <button
                             class="c_pub_button_add pub_btn_add_img"
                                 @click="uploadZIPFile(0)"
                           >
                             代码上传
-                          </button> -->
+                          </button>
                         </div>
                         <div
                           v-if="
@@ -3925,6 +3956,12 @@
                                   class="chapter_upload_l_i8"
                                   style="margin-left: 1px"
                                 ></div>
+
+                                <div
+                                  v-if="item1.type == 17"
+                                  class="chapter_upload_l_i8"
+                                  style="margin-left: 1px"
+                                ></div>
                               </div>
                               <div
                                 class="chapter_upload_ic"
@@ -8237,7 +8274,7 @@
     ></EnglishVoice>
     <appDialog ref="appDialog" @success="selectAppSuccess"></appDialog>
     <CodeEditor ref="CodeEditorRef" @success="addHtmlSuccess"></CodeEditor>
-    <selectHtmlPageDialog ref="selectHtmlPageDialogRef"/>
+    <selectHtmlPageDialog ref="selectHtmlPageDialogRef" @success="selectHtmlPageSuccess"/>
   </div>
 </template>
 
@@ -8287,7 +8324,7 @@ export default {
   },
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype: (window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       checkAll: false,
       chooseType: 1,
       checkedCities: [],
@@ -8543,7 +8580,8 @@ export default {
         "X",
         "Y",
         "Z"
-      ]
+      ],
+      changeId:""
     };
   },
   directives: {
@@ -14111,49 +14149,42 @@ export default {
     },
     // zip压缩文件上传
     uploadZIPFile(i){
-      this.$refs.selectHtmlPageDialogRef.open("测试");
-      // this.lineCount = i;
-      // // 只支持上传zip文件
-      // let input = document.createElement('input');
-      // input.type = 'file';
-      // input.accept = '.zip';
-      // input.style.display = 'none';
-      // // 只允许上传一个文件
-      // input.multiple = false;
-      // input.onchange = async (e) => {
-      //   let file = e.target.files[0];
-      //   if (!file) return;
-      //   if (file.type !== 'application/zip' && !file.name.endsWith('.zip')) {
-      //     this.$message.error('只支持上传zip文件');
-      //     return;
-      //   }
-      //   // this.awsupload({file:file,path:"zip/"+file.name}).then(res=>{
-      //   //   console.log('uploadZIPFile', res);
-      //   //   // 转成正常的网址
-      //   //   let url = res && res.Location ? decodeURIComponent(res.Location) : "";
-      //   //   console.log('正常网址:', url);
-
-      //   // })
-      //   // 这里可以根据实际需求进行上传处理
-      //   try{
-      //     const zip = new JSZip();
-      //     const content = await zip.loadAsync(file);
-      //     let _fileStructure = this.buildFileStructure(file,content);
-      //     let _time = new Date().getTime();
-      //     let _resultList = await this.uploadZipFileFn(_fileStructure.files,`${_time}_${_fileStructure.folderName}`);
-      //     console.log("_resultList",_resultList)
-
-      //   }catch(e){
-      //     console.log(e)
-      //     this.$message.error("解析zip文件失败")
-      //   }
 
-      // };
-      // document.body.appendChild(input);
-      // input.click();
-      // setTimeout(() => {
-      //   document.body.removeChild(input);
-      // }, 1000);
+      this.lineCount = i;
+      // 只支持上传zip文件
+      let input = document.createElement('input');
+      input.type = 'file';
+      input.accept = '.zip';
+      input.style.display = 'none';
+      // 只允许上传一个文件
+      input.multiple = false;
+      input.onchange = async (e) => {
+        let file = e.target.files[0];
+        if (!file) return;
+        if (file.type !== 'application/zip' && !file.name.endsWith('.zip')) {
+          this.$message.error('只支持上传zip文件');
+          return;
+        }
+        try{
+          const zip = new JSZip();
+          const content = await zip.loadAsync(file);
+          let _fileStructure = this.buildFileStructure(file,content);
+          let _time = new Date().getTime();
+          let _resultList = await this.uploadZipFileFn(_fileStructure.files,`${_time}_${_fileStructure.folderName}`);
+          this.changeId = "";
+          this.$refs.selectHtmlPageDialogRef.open(_resultList);
+
+        }catch(e){
+          console.log(e)
+          this.$message.error("解析zip文件失败")
+        }
+
+      };
+      document.body.appendChild(input);
+      input.click();
+      setTimeout(() => {
+        document.body.removeChild(input);
+      }, 1000);
     },
     // 构建文件结构树
     buildFileStructure(file,zip) {
@@ -14259,6 +14290,52 @@ export default {
         })
       })
     },
+    selectHtmlPageSuccess(data){
+      let _selectFile = data.find(i=>i.isSelect==="1");
+      if(!_selectFile){
+        this.changeId = "";
+        return this.$message.info("未选择主页面")
+      }
+
+      console.log("_selectFile",_selectFile)
+      let _index = this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+        0
+      ].chapterData.findIndex(i => i.type == 17 && i.id == this.changeId);
+      if (_index != -1) {
+        console.log("_index",_index)
+        this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+          0
+        ].chapterData[_index] = {
+          name: _selectFile.fileName,
+          title: _selectFile.fileName,
+          id:this.changeId,
+          url: _selectFile.url,
+          fileList:data,
+          type: 17
+        };
+      } else {
+        this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+          0
+        ].chapterData.push({
+          name: _selectFile.fileName,
+          title: _selectFile.fileName,
+          id:new Date().getTime(),
+          url: _selectFile.url,
+          fileList:data,
+          type: 17
+        });
+      }
+      this.changeId = "";
+      this.$forceUpdate();
+      this.$refs.selectHtmlPageDialogRef.close();
+    },
+    changeHTmlPage(itemTaskIndex,i){
+      let _data = this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+        itemTaskIndex
+      ].chapterData[i];
+      this.changeId = _data.id;
+      this.$refs.selectHtmlPageDialogRef.open(_data.fileList);
+    }
   },
   beforeDestroy() {
     clearTimeout(this.timer);

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

@@ -565,7 +565,7 @@ export default {
   },
   data() {
     return {
-        gotype:sessionStorage.getItem('gotype'),
+      gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       data: {
         isLoading: false,
         meta: {

+ 6 - 5
src/components/pages/inviteLoginSZ/inviteLogin.vue

@@ -51,7 +51,7 @@
 							</div>
 
 							<div :class="['c-b-r-m-btn',btnActive?'c-b-r-m-btnActive':'']" @click.stop="nextSteps">下一步</div>
-						
+
 						</div>
 						<div class="c-b-r-main" v-if="steps == 2">
 							<div class="c-b-r-m-title">请选择您的姓名</div>
@@ -222,6 +222,7 @@ export default {
 	align-items: center;
 	background-color: white;
 	position: relative;
+  overflow-x:hidden ;
 }
 
 .c-b-r-closeArea{
@@ -232,7 +233,7 @@ export default {
 	top: -45px;
 	border-radius: 50%;
 	background-color: #3681FC;
-	
+
 }
 
 .c-b-r-ca-btn{
@@ -322,7 +323,7 @@ export default {
 	margin-top: 20px;
 	display: flex;
 	flex-wrap: wrap;
-
+  overflow: auto;
 }
 
 .c-b-r-m-cna-none{
@@ -350,7 +351,7 @@ export default {
   background-color: #E0EAFB;
 	color:#3681FC;
 	border-color: #3681FC;
-	
+
 }
 
 
@@ -457,4 +458,4 @@ export default {
     justify-content: center !important;
     margin: 0 !important;
 } */
-</style>
+</style>

+ 15 - 2
src/components/pages/liyuan/CourseCon.vue

@@ -127,7 +127,15 @@ export default {
       this.getCourse();
     },
     lookMore(){
-        sessionStorage.setItem('gotype', this.$route.path);
+
+        try {
+          window.topU.gotype = this.$route.path
+        } catch (error) {
+          console.log(error);
+        }
+        console.log('betaL',betaL);
+        
+        // sessionStorage.setItem('gotype', this.$route.path);
         let to = `/pbl-student-table/dist/#/index?userid=${this.$route.query.userid}&oid=${this.$route.query.oid}&org=${this.$route.query.org}&role=${this.$route.query.role}&tType=${this.$route.query.tType}&cid=&screenType=3&gotype=1`
         let con = this.betaL =='beta'? 'https://beta.pbl.cocorobo.cn' : 'https://pbl.cocorobo.cn'
         console.log( `${con}${to}`);
@@ -265,7 +273,12 @@ export default {
        window.topU.postMessage({ cid: item.courseId, screenType: "3" }, "*");
     },
     goToCourse(courseId) {
-        sessionStorage.setItem('gotype', 'backCourseCon');
+        try {
+          window.topU.gotype = 'backCourseCon'
+        } catch (error) {
+          console.log(error);
+        }
+        // sessionStorage.setItem('gotype', 'backCourseCon');
 
         this.goToCourse4(courseId)
     },

+ 1 - 1
src/components/pages/liyuan/aiOffice.vue

@@ -58,7 +58,7 @@ export default {
 
 .cardBox{
   display: grid;
-  grid-template-columns: repeat(7, 1fr);
+  grid-template-columns: repeat(5, 1fr);
   gap: 20px;
   width: 100%;
   margin-top: 20px;

+ 8 - 2
src/components/pages/liyuan/components/backPage.vue

@@ -23,8 +23,14 @@
         },
         methods:{
             backO(){
-                this.$router.push({ path: sessionStorage.getItem('gotype'), query: { userid: this.userid, oid: this.oid, org: this.org, role: this.role, gotype: 1,tType:this.tType } })
-                sessionStorage.removeItem('gotype');
+                // sessionStorage.removeItem('gotype');
+                try {
+                    this.$router.push({ path: (window.topU && window.topU.gotype) ?  window.topU.gotype : '', query: { userid: this.userid, oid: this.oid, org: this.org, role: this.role, gotype: 1,tType:this.tType } })
+                    window.topU.gotype = '' 
+                } catch (error) {
+                    this.$router.go(-1)
+                    console.log(error);
+                }
             }
         },
         mounted(){

+ 9 - 2
src/components/pages/liyuan/components/card.vue

@@ -38,8 +38,15 @@ export default {
     },
     methods: {
         goTo() {
-            sessionStorage.setItem('gotype', this.$route.path);
-
+            try {
+                window.topU.gotype = this.$route.path
+                console.log('top',this.$route.path);
+            } catch (error) {
+                console.log(err);
+            }
+            // sessionStorage.setItem('gotype', this.$route.path);
+            console.log('betaL',betaL);
+            
             if (this.type == 1) {    
                 this.$router.push({ path: this.to, query: { userid: this.userid, oid: this.oid, org: this.org, role: this.role,tType: this.tType, gotype: 1,sortId:this.sortId } })
             }else if (this.type == 2) {

+ 1 - 1
src/components/pages/liyuan/page/examine/index.vue

@@ -237,7 +237,7 @@ export default {
   },
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       pType: 2,
       allData: {
         type: 1,

+ 1 - 1
src/components/pages/liyuan/page/portrait/index.vue

@@ -228,7 +228,7 @@ export default {
   },
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       teachingActivityNum: 0,
       teachingAndResearchActivitiesNum: 0,
       trainingActivityNum: 0,

+ 1 - 1
src/components/pages/liyuan/page/student.vue

@@ -229,7 +229,7 @@ export default {
   },
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       tableHeight: "500px",
       isLoading: false,
       formLabelWidth: "100px",

+ 264 - 8
src/components/pages/newCourse/addCourse.vue

@@ -1209,6 +1209,12 @@
                                     class="chapter_upload_l_i15"
                                     style="margin-left: 1px"
                                   ></div>
+
+                                  <div
+                                    v-if="item1.type == 17"
+                                    class="chapter_upload_l_i8"
+                                    style="margin-left: 1px"
+                                  ></div>
                                   </div>
                                   <div class="chapter_upload_n">
                                     <input
@@ -1294,6 +1300,24 @@
                                       readonly="true"
                                       @click="selectLine(itemTaskIndex, index1)"
                                     />
+
+                                    <input
+                                    :placeholder="
+                                      item1.title ? item1.title : '代码上传'
+                                    "
+                                    v-if="item1.type == 17"
+                                    style="
+                                  border: none;
+                                  outline: none;
+                                  width: 80%;
+                                  white-space: nowrap;
+                                  overflow: hidden;
+                                  text-overflow: ellipsis;
+                                "
+                                    readonly="true"
+                                    @click="changeHTmlPage(itemTaskIndex, index1)"
+                                  />
+
                                     <input
                                       :placeholder="
                                         item1.title ? item1.title : '链接'
@@ -1411,6 +1435,13 @@
                                     >
                                       <div></div>
                                     </div>
+                                    <div
+                                    class="chapter_upload_ic_edit"
+                                    v-if="item1.type == 17"
+                                    @click="changeHTmlPage(itemTaskIndex, index1)"
+                                  >
+                                    <div></div>
+                                  </div>
                                     <div
                                       class="chapter_upload_ic_edit"
                                       v-if="item1.type == 14"
@@ -1492,13 +1523,20 @@
                           >
                             智能应用
                           </button>
-                          
+
                            <button
                             class="c_pub_button_add pub_btn_add_img"
                                 @click="openCodeEditor(0,'',unitIndex,itemTaskIndex ,'')"
                           >
                             代码编辑器
                           </button>
+
+                          <button
+                            class="c_pub_button_add pub_btn_add_img"
+                                @click="uploadZIPFile(itemTaskIndex)"
+                          >
+                            代码上传
+                          </button>
                           </div>
                           <div
                             v-if="
@@ -1683,6 +1721,12 @@
                                     class="chapter_upload_l_i15"
                                     style="margin-left: 1px"
                                   ></div>
+
+                                  <div
+                                    v-if="item1.type == 17"
+                                    class="chapter_upload_l_i8"
+                                    style="margin-left: 1px"
+                                  ></div>
                                   </div>
                                   <div class="chapter_upload_n">
                                     <span
@@ -1760,6 +1804,23 @@
                                       @click="selectLine(itemTaskIndex, index1)"
                                     />
 
+                                    <input
+                                    :placeholder="
+                                      item1.title ? item1.title : '代码上传'
+                                    "
+                                    v-if="item1.type == 17"
+                                    style="
+                                  border: none;
+                                  outline: none;
+                                  width: 80%;
+                                  white-space: nowrap;
+                                  overflow: hidden;
+                                  text-overflow: ellipsis;
+                                "
+                                    readonly="true"
+                                    @click="changeHTmlPage(itemTaskIndex, index1)"
+                                  />
+
                                     <input
                                     :placeholder="
                                       item1.title ? item1.title : 'Ai应用'
@@ -7491,7 +7552,7 @@
     ></EnglishVoice>
     <appDialog ref="appDialog" @success="selectAppSuccess"></appDialog>
     <CodeEditor ref="CodeEditorRef" @success="addHtmlSuccess"></CodeEditor>
-
+    <selectHtmlPageDialog ref="selectHtmlPageDialogRef" @success="selectHtmlPageSuccess"/>
   </div>
 </template>
 
@@ -7515,6 +7576,7 @@ import EnglishVoice from "../EnglishVoice/index.vue";
 import appDialog from '../components/appDialog.vue'
 import { myMixin } from "@/mixins/mixin.js"
 import CodeEditor from "../components/CodeEditor";
+import { uploadFileMixin } from "../../tools/uploadFileMixin.js";
 
 var OpenCC = require("opencc-js");
 let converter = OpenCC.Converter({
@@ -7522,8 +7584,11 @@ let converter = OpenCC.Converter({
 		to:'cn'
 })
 
+import JSZip from 'jszip'
+import selectHtmlPageDialog from '../dialog/selectHtmlPageDialog.vue'
+
 export default {
-  mixins: [ myMixin ],
+  mixins: [ myMixin,uploadFileMixin ],
   components: {
     CodeEditor,
     EditorBar,
@@ -7538,10 +7603,11 @@ export default {
     evaBox,
     EnglishVoice,
     appDialog,
+    selectHtmlPageDialog,
   },
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       checkAll: false,
       checkAll2: false,
       chooseType: 1,
@@ -7827,8 +7893,8 @@ export default {
       twoJson: [],
       oneJson: [],
       updateKey:1,
-      optionTypeList:['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
-
+      optionTypeList:['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'],
+      changeId:"",
     };
   },
   directives: {
@@ -14600,7 +14666,7 @@ export default {
       console.log('addHtmlSuccess',name,url,'type:',type,'unitIndex',unitIndex,'itemTaskIndex',itemTaskIndex,'index1',index1);
       if (type == 1) {
         this.unitJson[unitIndex].chapterInfo[0].taskJson[
-          itemTaskIndex 
+          itemTaskIndex
         ].chapterData.splice(index1,1,{
           name: Tname,
           url: url,
@@ -14608,7 +14674,7 @@ export default {
         })
       }else{
         this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
-          itemTaskIndex 
+          itemTaskIndex
         ].chapterData.push({
           name: Tname,
           url: url,
@@ -14662,6 +14728,196 @@ export default {
       }
       this.imgChange1(null, null, 8, this.lineCount);
       this.dialogVisible7 = false;
+    },
+    // zip压缩文件上传
+    uploadZIPFile(i){
+
+    this.lineCount = i;
+    // 只支持上传zip文件
+    let input = document.createElement('input');
+    input.type = 'file';
+    input.accept = '.zip';
+    input.style.display = 'none';
+    // 只允许上传一个文件
+    input.multiple = false;
+    input.onchange = async (e) => {
+      let file = e.target.files[0];
+      if (!file) return;
+      if (file.type !== 'application/zip' && !file.name.endsWith('.zip')) {
+        this.$message.error('只支持上传zip文件');
+        return;
+      }
+      try{
+        const zip = new JSZip();
+        const content = await zip.loadAsync(file);
+        let _fileStructure = this.buildFileStructure(file,content);
+        let _time = new Date().getTime();
+        let _resultList = await this.uploadZipFileFn(_fileStructure.files,`${_time}_${_fileStructure.folderName}`);
+        this.changeId = "";
+        this.$refs.selectHtmlPageDialogRef.open(_resultList);
+
+      }catch(e){
+        console.log(e)
+        this.$message.error("解析zip文件失败")
+      }
+
+    };
+    document.body.appendChild(input);
+    input.click();
+    setTimeout(() => {
+      document.body.removeChild(input);
+    }, 1000);
+    },
+    // 构建文件结构树
+    buildFileStructure(file,zip) {
+    const root = {
+      folderName: file.name.replace(/\.[^/.]+$/, ""), // 移除扩展名
+      files: []
+    };
+
+    // 遍历ZIP文件中的所有文件/文件夹
+    zip.forEach((relativePath, file) => {
+      if (file.dir) return; // 跳过目录
+
+      const parts = relativePath.split('/');
+      let currentLevel = root.files;
+
+      for (let i = 0; i < parts.length; i++) {
+        const part = parts[i];
+        const isLast = i === parts.length - 1;
+
+        if (isLast) {
+          // 添加文件
+          currentLevel.push({fileName:part,file:file});
+        } else {
+          // 查找或创建文件夹
+          let folder = currentLevel.find(item =>
+            typeof item === 'object' && item.folderName === part
+          );
+
+          if (!folder) {
+            folder = {
+              folderName: part,
+              files: []
+            };
+            currentLevel.push(folder);
+          }
+
+          currentLevel = folder.files;
+        }
+      }
+    });
+
+    return root;
+    },
+    //按路径上传文件
+    async uploadZipFileFn(fileList,path){
+    return new Promise(async (resolve)=>{
+      let _copyFileList = fileList;
+
+      let promise = [];
+      for(let i = 0; i < _copyFileList.length; i++){
+        if(_copyFileList[i].folderName){
+          let _path = `${path}/${_copyFileList[i].folderName}`;
+          promise.push(this.uploadZipFileFn(_copyFileList[i].files,_path).then(res=>{
+            _copyFileList[i].files = res;
+          }))
+        }else if(_copyFileList[i].fileName){
+          // 将 ZIP 条目转换为文件对象
+          const blob = await _copyFileList[i].file.async('blob');
+          // 根据文件名设置type
+          let type = 'text/html';
+          if (_copyFileList[i].fileName.endsWith('.js')) {
+            type = 'application/javascript';
+          } else if (_copyFileList[i].fileName.endsWith('.css')) {
+            type = 'text/css';
+          } else if (_copyFileList[i].fileName.endsWith('.json')) {
+            type = 'application/json';
+          } else if (_copyFileList[i].fileName.endsWith('.png')) {
+            type = 'image/png';
+          } else if (_copyFileList[i].fileName.endsWith('.jpg') || _copyFileList[i].fileName.endsWith('.jpeg')) {
+            type = 'image/jpeg';
+          } else if (_copyFileList[i].fileName.endsWith('.gif')) {
+            type = 'image/gif';
+          } else if (_copyFileList[i].fileName.endsWith('.svg')) {
+            type = 'image/svg+xml';
+          } else if (_copyFileList[i].fileName.endsWith('.html') || _copyFileList[i].fileName.endsWith('.htm')) {
+            type = 'text/html';
+          } else if (_copyFileList[i].fileName.endsWith('.txt')) {
+            type = 'text/plain';
+          } else if (_copyFileList[i].fileName.endsWith('.pdf')) {
+            type = 'application/pdf';
+          } else if (_copyFileList[i].fileName.endsWith('.mp3')) {
+            type = 'audio/mpeg';
+          } else if (_copyFileList[i].fileName.endsWith('.mp4')) {
+            type = 'video/mp4';
+          } else if (_copyFileList[i].fileName.endsWith('.zip')) {
+            type = 'application/zip';
+          } else if (_copyFileList[i].fileName.endsWith('.xml')) {
+            type = 'application/xml';
+          } else if (_copyFileList[i].fileName.endsWith('.csv')) {
+            type = 'text/csv';
+          } else if (_copyFileList[i].fileName.endsWith('.md')) {
+            type = 'text/markdown';
+          }
+          let _file = new File([blob], _copyFileList[i].fileName, {type: type, lastModified: new Date().getTime()});
+          promise.push(this.awsupload({file:_file,path:`${path}/${_copyFileList[i].fileName}`}).then(res=>{
+            delete _copyFileList[i].file;
+            _copyFileList[i].url = decodeURIComponent(res.Location);
+          }))
+        }
+      }
+      Promise.all(promise).then(res=>{
+        resolve(_copyFileList);
+      })
+    })
+    },
+    selectHtmlPageSuccess(data){
+    let _selectFile = data.find(i=>i.isSelect==="1");
+    if(!_selectFile){
+      this.changeId = "";
+      return this.$message.info("未选择主页面")
+    }
+
+    console.log("_selectFile",_selectFile)
+    let _index = this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+    this.lineCount
+    ].chapterData.findIndex(i => i.type == 17 && i.id == this.changeId);
+    if (_index != -1) {
+      console.log("_index",_index)
+      this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+        this.lineCount
+      ].chapterData[_index] = {
+        name: _selectFile.fileName,
+        title: _selectFile.fileName,
+        id:this.changeId,
+        url: _selectFile.url,
+        fileList:data,
+        type: 17
+      };
+    } else {
+      this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+      this.lineCount
+      ].chapterData.push({
+        name: _selectFile.fileName,
+        title: _selectFile.fileName,
+        id:new Date().getTime(),
+        url: _selectFile.url,
+        fileList:data,
+        type: 17
+      });
+    }
+    this.changeId = "";
+    this.$forceUpdate();
+    this.$refs.selectHtmlPageDialogRef.close();
+    },
+    changeHTmlPage(itemTaskIndex,i){
+      let _data = this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
+        itemTaskIndex
+      ].chapterData[i];
+      this.lineCount = itemTaskIndex;
+      this.changeId = _data.id;
+      this.$refs.selectHtmlPageDialogRef.open(_data.fileList);
     }
   },
   beforeDestroy() {

+ 1 - 1
src/components/pages/pptEasy/addCourse.vue

@@ -2406,7 +2406,7 @@ export default {
   },
   data() {
     return {
-      gotype: sessionStorage.getItem("gotype"),
+      gotype: (window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       checkAll: false,
       chooseType: 1,
       checkedCities: [],

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

@@ -309,7 +309,7 @@ export default {
   components: { EditorBar,backPage },
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       itemCount: 1,
       courseTitle: "",
       courseText: "",

+ 1 - 1
src/components/pages/sz/teacher.vue

@@ -321,7 +321,7 @@ export default {
     },
   data() {
     return {
-      gotype: sessionStorage.getItem('gotype'),
+      gotype: (window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       tableHeight: "500px",
       isLoading: false,
       formLabelWidth: "100px",

+ 1 - 1
src/components/pages/teacherOffice/index.vue

@@ -344,7 +344,7 @@ export default {
 
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       tableHeight: "500px",
       isLoading: false,
       formLabelWidth: "100px",

+ 1 - 1
src/components/pages/test/add/addTest.vue

@@ -73,7 +73,7 @@ export default {
     },
     data() {
         return {
-            gotype:sessionStorage.getItem('gotype'),
+            gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
             userid: this.$route.query.userid,
             oid: this.$route.query.oid,
             org: this.$route.query.org,

+ 1 - 1
src/components/pages/test/check/index.vue

@@ -2147,7 +2147,7 @@ export default {
   },
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       aiscoId:'',
       aiscoLoading:true,
       cueWord:{

+ 1 - 1
src/components/pages/test/examine/index.vue

@@ -102,7 +102,7 @@ export default {
   },
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       aArray: [],
       bArray: [],
       timeListA:[],

+ 1 - 1
src/components/pages/test/index.vue

@@ -443,7 +443,7 @@ export default {
     components: { EditorBar, CourseProblem, pie1, pie2, randar1, randar2, shareBox, examine, aggregate,backPage },
     data() {
         return {
-            gotype:sessionStorage.getItem('gotype'),
+            gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
             examineData: [],
             cutNumber: 0,
             itemCount: 1,

+ 1 - 1
src/components/pages/testStudent/view/preview.vue

@@ -69,7 +69,7 @@ export default {
   },
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       userid: this.$route.query.userid,
       oid: this.$route.query.oid,
       org: this.$route.query.org,

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

@@ -552,7 +552,7 @@ export default {
   },
   data() {
     return {
-      gotype:sessionStorage.getItem('gotype'),
+      gotype:(window.topU && window.topU.gotype) ?  window.topU.gotype : '',
       worksDialog:false,
       exportW:0,
       digNum:0,

Некоторые файлы не были показаны из-за большого количества измененных файлов