SanHQin 22 tuntia sitten
vanhempi
commit
575efec76d

+ 1 - 1
dist/index.html

@@ -32,7 +32,7 @@
       width: 100%;
       background: #e6eaf0;
       font-family: '黑体';
-    }</style><link href=./static/css/app.a0b88c4e1b9c2d46f8d78773ce64cca4.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.bb486323f0fa002ba2e7.js></script><script type=text/javascript src=./static/js/app.e8f5a3c765fb7ea4cfa0.js></script></body></html><script>function stopSafari() {
+    }</style><link href=./static/css/app.abdf3b127f860435a33b7512bf3e1a43.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.bb486323f0fa002ba2e7.js></script><script type=text/javascript src=./static/js/app.adc441610cd032a2719e.js></script></body></html><script>function stopSafari() {
     //阻止safari浏览器双击放大功能
     let lastTouchEnd = 0  //更新手指弹起的时间
     document.documentElement.addEventListener("touchstart", function (event) {

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
dist/static/css/app.abdf3b127f860435a33b7512bf3e1a43.css


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
dist/static/css/app.abdf3b127f860435a33b7512bf3e1a43.css.map


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
dist/static/js/app.adc441610cd032a2719e.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
dist/static/js/app.adc441610cd032a2719e.js.map


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
dist/static/js/manifest.161e82026ac2ae03ab6f.js.map


+ 23 - 3
src/components/pages/classroomObservation/dialog/batchCreationClassDialog.vue

@@ -337,7 +337,9 @@ export default {
                 type: "generateReport",
                 text: "生成报告",
                 status: "0",
-                progress: "0"
+                progress: "0",
+                num: _analysisList.length,
+                successNum: 0
               },
               {
                 type: "createClass",
@@ -397,7 +399,9 @@ export default {
                 type: "generateReport",
                 text: "生成报告",
                 status: "0",
-                progress: "0"
+                progress: "0",
+                num: _analysisList.length,
+                successNum: 0
               },
               {
                 type: "createClass",
@@ -459,7 +463,9 @@ export default {
                 type: "generateReport",
                 text: "生成报告",
                 status: "0",
-                progress: "0"
+                progress: "0",
+                num: _analysisList.length,
+                successNum: 0
               },
               {
                 type: "createClass",
@@ -795,6 +801,7 @@ export default {
               .find(i => i.id === id)
               .jsonData.steps.find(i => i.type == "generateReport").status =
               "0";
+              this.dataList.find(i => i.id === id).jsonData.steps.find(i => i.type == "generateReport").successNum = 0;
               this.dataList
               .find(i => i.id === id)
               .jsonData.steps.find(i => i.type == "createClass").status =
@@ -1209,6 +1216,7 @@ export default {
           } else if (_step.type === "generateReport") {
             //生成报告
             _stepList[i].status = "2";
+            _stepList[i].successNum = 0;
             _stepList[i].startTime =
               new Date().toLocaleDateString().replaceAll("/", "-") +
               " " +
@@ -1217,6 +1225,7 @@ export default {
             this.dataList.find(
               i => i.id === _startData.id
             ).jsonData.steps = _stepList;
+            let _i = i;
             this.$forceUpdate()
             let _analysisList = _startData.jsonData.analysisList;
 
@@ -1282,7 +1291,17 @@ export default {
                     _startData.jsonData.analysisList[index].status = "success";
                     _startData.jsonData.analysisList[index].jsonData =
                       data.data;
+                    _stepList[_i].successNum += 1;
+                    this.dataList.find(i2 => i2.id === _startData.id).jsonData.steps[_i].successNum = _stepList[_i].successNum;
+                    this.$forceUpdate();
                     resolve();
+                
+                    // this.updateTask(_startData.id);
+                    // _startData.jsonData = JSON.parse(
+                    //   JSON.stringify(
+                    //     this.dataList.find(i => i.id === _startData.id).jsonData
+                    //   )
+                    // );
                   }
                 };
                 getAnalysis();
@@ -1586,6 +1605,7 @@ export default {
             .jsonData.steps.find(i2 => i2.type == "generateReport").status =
             "0";
         });
+        this.dataList.find(i => i.id === id).jsonData.steps.find(i => i.type == "generateReport").successNum = 0;
 
         if (!this.dataList.some(i => i.status == "1")) {
           this.startTask(_generateList[0].id);

+ 4 - 4
src/components/pages/classroomObservation/newComponents/batchClassCard.vue

@@ -68,7 +68,7 @@
                   src="../../../../assets/icon/classroomObservation/isDoStatus_icon.svg"
                   v-if="item.status=='2'"
                 />
-                <div>{{ item.text }}</div>
+                <div>{{ item.text }}<span v-if="item.num">({{ item.successNum }}/{{ item.num }})</span></div>
                 <span>
                   <span v-if="item.startTime">{{ item.startTime }}</span>
                   <!-- <span
@@ -112,7 +112,7 @@
                   src="../../../../assets/icon/classroomObservation/isDoStatus_icon.svg"
                   v-if="item.status=='2'"
                 />
-                <div>{{ item.text }}</div>
+                <div>{{ item.text }}<span v-if="item.num">({{ item.successNum }}/{{ item.num }})</span></div>
                 <span>
                   <span v-if="item.startTime">{{ item.startTime }}</span>
                   <!-- <span
@@ -431,7 +431,7 @@ export default {
 }
 
 .stepBox {
-  width: 315px;
+  width: 350px;
   height: auto;
   background-color: #fff;
   position: absolute;
@@ -475,7 +475,7 @@ export default {
   display: flex;
   align-items: center;
   justify-content: center;
-  width: 150px;
+  width: 260px;
   height: 100%;
   color: rgba(54, 129, 252, 1);
 }

+ 161 - 4
src/components/pages/easy/addCourse.vue

@@ -786,6 +786,12 @@
                               <input type="file" accept="*" style="display: none" v-if="inputShow" @change="beforeUpload2($event, unitIndex, 12, itemTaskIndex)
                                 " />
                             </button> -->
+                            <!-- <button
+                            class="c_pub_button_add pub_btn_add_img"
+                                @click="uploadZIPFile(0)"
+                          >
+                            ZIP文件上传
+                          </button> -->
                         </div>
                         <div
                           v-if="
@@ -8211,15 +8217,17 @@ import englishRight from "./commpont/englishRight.vue";
 import EnglishVoice from "../EnglishVoice/index.vue";
 import appDialog from "../components/appDialog.vue";
 import { myMixin } from "@/mixins/mixin.js"
+import { uploadFileMixin } from "../../tools/uploadFileMixin.js";
 import CodeEditor from "../components/CodeEditor";
 var OpenCC = require("opencc-js");
 let converter = OpenCC.Converter({
   from: "hk",
   to: "cn"
 });
+import JSZip from 'jszip'
 
 export default {
-  mixins: [ myMixin ],
+  mixins: [ myMixin,uploadFileMixin],
   components: {
     CodeEditor,
     EditorBar,
@@ -13977,7 +13985,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,
@@ -13985,7 +13993,7 @@ export default {
         })
       }else{
         this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
-          itemTaskIndex 
+          itemTaskIndex
         ].chapterData.push({
           name: Tname,
           url: url,
@@ -14039,7 +14047,156 @@ 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;
+        }
+        // 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.uploadZipFile(_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);
+    },
+    // 构建文件结构树
+    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 uploadZipFile(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.uploadZipFile(_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);
+        })
+      })
+    },
   },
   beforeDestroy() {
     clearTimeout(this.timer);

+ 293 - 0
src/components/tools/uploadFileMixin.js

@@ -0,0 +1,293 @@
+import '../../common/aws-sdk-2.235.1.min.js'
+export const uploadFileMixin = {
+  data() {
+    return {
+      bucket: "", //aws上传接口
+      bucketname: "ccrb", //桶
+      partsize: 10 * 1024 * 1024, //10MB  分片
+      uploadid: "",
+    }
+  },
+  methods: {
+    //--------------------------分断上传保证稳定性
+    //初始化上传
+    // async init(){
+    // 	const credentials = {
+    // 	    accessKeyId: "AKIATLPEDU37QV5CHLMH",
+    // 	    secretAccessKey: "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",
+    // 	}; //秘钥形式的登录上传
+    // 	window.AWS.config.update(credentials);
+    // 	window.AWS.config.region = "cn-northwest-1"; //设置区域
+    // 	//桶的设置
+    // 	bucket = new window.AWS.S3({
+    // 	    params: {
+    // 	        Bucket: this.bucketname
+    // 	    }
+    // 	});
+    // 	return bucket;
+    // },
+    // 初始化上传入口
+    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) {
+      //key可以设置为桶的相对路径,Body为文件, ACL最好要设置
+      var params = {
+        Bucket: this.bucketname,
+        Key: keyname,
+        // ContentType: file.type,
+        PartNumber: pn,
+        UploadId: uploadid,
+        Body: file.slice(start, end),
+        // "Access-Control-Allow-Credentials": "*",
+        // ACL: "public-read",
+      };
+      const result = await this.bucket.uploadPart(params).promise();
+      return { ETag: result.ETag, PartNumber: pn };
+    },
+    //完成分块上传
+    async completeMultipartUpload(parts, keyname, uploadid) {
+      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,
+    //   };
+    //   let data = await this.bucket.abortMultipartUpload(params).promise();
+    //   this.$emit("delUpload", { index: this.index })
+
+    // },
+    //--------------------------------下面支持断点续传
+
+    //初始化亚马逊参数
+    async init() {
+      //秘钥形式的登录上传
+      const credentials = {
+        accessKeyId: "AKIATLPEDU37QV5CHLMH",
+        secretAccessKey: "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",
+        region: "cn-northwest-1",
+      };
+      window.AWS.config.update(credentials);
+      // window.AWS.config.region = "cn-northwest-1"; //设置区域
+      //桶的设置
+      this.bucket = new window.AWS.S3({
+        params: {
+          Bucket: this.bucketname,
+        },
+      });
+      return this.bucket;
+    },
+
+    //获取当前文件是否有已上传断点信息
+    async getawscheckpoint(key) {
+      let partsinfo;
+      try {
+        const result = await this.bucket
+          .listMultipartUploads({ Bucket: this.bucketname, Prefix: key })
+          .promise();
+        //获取具体分片信息
+        if (result.Uploads.length) {
+          this.uploadid = result.Uploads[result.Uploads.length - 1].UploadId;
+          partsinfo = await this.bucket
+            .listParts({
+              Bucket: this.bucketname,
+              Key: key,
+              UploadId: this.uploadid,
+            })
+            .promise();
+        }
+      } catch (err) {
+        console.log(err);
+      }
+      return { uploadid: this.uploadid, partsinfo };
+    },
+
+    //分段上传
+    async awsuploadpart(file, uploadid, parts, key) {
+      var partarr = []; //已完成的数组
+      //已完成的分片,转化成提交格式
+      const completeparts = parts.map((_) => {
+        partarr.push(_.PartNumber);
+        return { PartNumber: _.PartNumber, ETag: _.ETag };
+      });
+      // 分块上传文件
+      // parts = [];
+      let uploadpart;
+      let start = 0;
+      let end = 0;
+      let len = Math.ceil(file.size / this.partsize); //循环的长度
+      //循环上传
+      for (let i = 0; i < len; i++) {
+        start = i * this.partsize;
+        end = (i + 1) * this.partsize;
+        if (!partarr.includes(i + 1)) {
+          uploadpart = await this.uploadPart(
+            file,
+            key,
+            uploadid,
+            i + 1,
+            start,
+            end
+          );
+          if (uploadpart.ETag != null) {
+            completeparts.push(uploadpart);
+            partarr.push(uploadpart.PartNumber);
+          } else {
+            return;
+          }
+        }
+      }
+      //提交上传成功信息
+      let data = await this.completeMultipartUpload(
+        completeparts,
+        key,
+        uploadid
+      );
+      return data;
+    },
+
+    //上传的接口
+    async awsupload({ file, path }) {
+
+      return new Promise((resolve) => {
+        if (!file) {
+          this.$message.error("请上传文件")
+          return resolve(false)
+        };
+        this.init(); //初始化桶
+
+        let key = path;
+        if (!key) {
+          key = `default/${file.name.split(".")[0] + new Date().getTime() + "." + file.name.split(".")[file.name.split(".").length - 1]}`;
+        }
+        let params = {
+          Bucket: this.bucketname,
+          Key: key,
+        };
+        console.log('awsupload', file, path)
+        try {
+          //检查文件是否已上传
+          this.bucket.headObject(params, async (err, data) => {
+            // 没有上传成功,head方法会返回失败
+            if (err) {
+              //检查是否部分上传
+              const { uploadid, partsinfo } = await this.getawscheckpoint(
+                key,
+                this.bucket
+              );
+              //如果已经部分存在,那么直接在节点续传
+              if (uploadid) {
+                //断点续传
+                let data = await this.awsuploadpart(
+                  file,
+                  uploadid,
+                  partsinfo.Parts,
+                  key
+                );
+                return resolve(data)
+              }
+              //不存在,上传新的
+              else {
+                const uploadid = await this.initMultipartUpload(key, file); //初始化文件上传
+                let data = await this.awsuploadpart(
+                  file,
+                  uploadid,
+                  [],
+                  key
+                );
+                return resolve(data)
+              }
+            }
+            //如果已经上传成功了,那么直接返回状态百分百
+            else if (data) {
+              //data存在,上传成功
+              let url = `https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/${key}`
+              resolve({
+                Key: key,
+                Location: url,
+                ETag: data.ETag,
+                size: data.ContentLength,
+                ServerSideEncryption: data.ServerSideEncryption,
+                Bucket: this.bucketname
+              })
+            }
+          });
+        } catch (e) {
+          console.log("上传文件失败", e)
+          resolve(false);
+
+        }
+      })
+    },
+
+    //正常上传
+    defaultUploadFile(file, key) {
+      // const loading = this.openLoading();
+
+      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"; //设置区域
+  
+        var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } }); //选择桶
+        var _this = this;
+  
+        if (file) {
+          var params = {
+            Key: key,
+            ContentType: file.type,
+            Body: file,
+            "Access-Control-Allow-Credentials": "*",
+            ACL: "public-read"
+          }; //key可以设置为桶的相抵路径,Body为文件, ACL最好要设置
+          var options = {
+            partSize: 2048 * 1024 * 1024,
+            queueSize: 2,
+            leavePartsOnError: true
+          };
+          bucket
+            .upload(params, options)
+            .on("httpUploadProgress", function (evt) {
+              //这里可以写进度条
+              // console.log("Uploaded : " + parseInt((evt.loaded * 80) / evt.total) + '%');
+            })
+            .send(function (err, data) {
+              // loading.close();
+              if (err) {
+                // var a = _this.$refs.upload1.uploadFiles;
+                // a.splice(a.length - 1, a.length);
+                resolve("")
+              } else {
+                resolve({
+                  name: file.name,
+                  url: data.Location,
+                  uid: file.uid
+                })
+  
+              }
+            });
+        }
+      })
+    },
+  }
+};

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä