SanHQin 2 hónapja
szülő
commit
84bf8046a6

+ 1 - 1
dist/index.html

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

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/static/css/app.b3b54293cb15652faa8e512ce218aac4.css


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/static/css/app.b3b54293cb15652faa8e512ce218aac4.css.map


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/static/js/0.4f3b05586c3acc102a54.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/static/js/0.4f3b05586c3acc102a54.js.map


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/static/js/0.df8814bab917ab2583e0.js.map


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/static/js/app.ce06d3c7064b7d5f54f2.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/static/js/app.ce06d3c7064b7d5f54f2.js.map


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

@@ -1,2 +1,2 @@
-!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
+!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

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/static/js/manifest.161e82026ac2ae03ab6f.js.map


+ 4 - 0
src/assets/icon/classroomObservation/isDoStatus_icon.svg

@@ -0,0 +1,4 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path opacity="0.5" d="M7.00008 1.16663C5.84636 1.16663 4.71854 1.50875 3.75926 2.14972C2.79997 2.79069 2.0523 3.70174 1.61079 4.76764C1.16928 5.83354 1.05376 7.00643 1.27884 8.13799C1.50392 9.26954 2.05949 10.3089 2.87529 11.1247C3.6911 11.9406 4.7305 12.4961 5.86206 12.7212C6.99361 12.9463 8.1665 12.8308 9.2324 12.3893C10.2983 11.9477 11.2093 11.2001 11.8503 10.2408C12.4913 9.2815 12.8334 8.15368 12.8334 6.99996C12.8334 6.23391 12.6825 5.47537 12.3894 4.76764C12.0962 4.05991 11.6665 3.41684 11.1249 2.87517C10.5832 2.33349 9.94014 1.90381 9.2324 1.61066C8.52467 1.31751 7.76613 1.16663 7.00008 1.16663ZM7.00008 11.6666C6.0771 11.6666 5.17485 11.3929 4.40742 10.8801C3.63999 10.3674 3.04186 9.63854 2.68865 8.78581C2.33544 7.93309 2.24302 6.99478 2.42309 6.08954C2.60315 5.18429 3.04761 4.35277 3.70025 3.70013C4.3529 3.04748 5.18442 2.60303 6.08966 2.42296C6.99491 2.2429 7.93322 2.33531 8.78594 2.68852C9.63866 3.04173 10.3675 3.63987 10.8803 4.4073C11.3931 5.17473 11.6667 6.07698 11.6667 6.99996C11.6667 8.23764 11.1751 9.42462 10.2999 10.2998C9.42475 11.175 8.23776 11.6666 7.00008 11.6666Z" fill="#3681FC"/>
+<path d="M11.6667 6.99996L12.8333 6.99996C12.8333 6.23392 12.6825 5.47537 12.3893 4.76764C12.0961 4.05991 11.6665 3.41685 11.1248 2.87517C10.5831 2.33349 9.94005 1.90381 9.23232 1.61066C8.52459 1.31751 7.76604 1.16663 7 1.16663V2.33329C8.23768 2.33329 9.42466 2.82496 10.2998 3.70013C11.175 4.5753 11.6667 5.76228 11.6667 6.99996Z" fill="#3681FC"/>
+</svg>

+ 10 - 0
src/assets/icon/classroomObservation/successStatus_icon.svg

@@ -0,0 +1,10 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_2421_25813)">
+<path d="M7 0.875C5.78859 0.875 4.60439 1.23423 3.59713 1.90725C2.58988 2.58027 1.80483 3.53687 1.34124 4.65606C0.877654 5.77526 0.756358 7.00679 0.992693 8.19493C1.22903 9.38306 1.81238 10.4744 2.66897 11.331C3.52557 12.1876 4.61694 12.771 5.80507 13.0073C6.99321 13.2436 8.22474 13.1223 9.34394 12.6588C10.4631 12.1952 11.4197 11.4101 12.0928 10.4029C12.7658 9.39562 13.125 8.21141 13.125 7C13.125 5.37555 12.4797 3.81763 11.331 2.66897C10.1824 1.52031 8.62445 0.875 7 0.875ZM6.125 9.44563L3.9375 7.25813L4.63313 6.5625L6.125 8.05437L9.36688 4.8125L10.0651 5.50638L6.125 9.44563Z" fill="#BCE685"/>
+</g>
+<defs>
+<clipPath id="clip0_2421_25813">
+<rect width="14" height="14" fill="white"/>
+</clipPath>
+</defs>
+</svg>

+ 4 - 0
src/assets/icon/classroomObservation/waitStatus_icon.svg

@@ -0,0 +1,4 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path opacity="0.5" d="M7.00008 1.16663C5.84636 1.16663 4.71854 1.50875 3.75926 2.14972C2.79997 2.79069 2.0523 3.70174 1.61079 4.76764C1.16928 5.83354 1.05376 7.00643 1.27884 8.13799C1.50392 9.26954 2.05949 10.3089 2.87529 11.1247C3.6911 11.9406 4.7305 12.4961 5.86206 12.7212C6.99361 12.9463 8.1665 12.8308 9.2324 12.3893C10.2983 11.9477 11.2093 11.2001 11.8503 10.2408C12.4913 9.2815 12.8334 8.15368 12.8334 6.99996C12.8334 6.23391 12.6825 5.47537 12.3894 4.76764C12.0962 4.05991 11.6665 3.41684 11.1249 2.87517C10.5832 2.33349 9.94014 1.90381 9.2324 1.61066C8.52467 1.31751 7.76613 1.16663 7.00008 1.16663ZM7.00008 11.6666C6.0771 11.6666 5.17485 11.3929 4.40742 10.8801C3.63999 10.3674 3.04186 9.63854 2.68865 8.78581C2.33544 7.93309 2.24302 6.99478 2.42309 6.08954C2.60315 5.18429 3.04761 4.35277 3.70025 3.70013C4.3529 3.04748 5.18442 2.60303 6.08966 2.42296C6.99491 2.2429 7.93322 2.33531 8.78594 2.68852C9.63866 3.04173 10.3675 3.63987 10.8803 4.4073C11.3931 5.17473 11.6667 6.07698 11.6667 6.99996C11.6667 8.23764 11.1751 9.42462 10.2999 10.2998C9.42475 11.175 8.23776 11.6666 7.00008 11.6666Z" fill="#969BA3"/>
+<path d="M11.6667 6.99996L12.8333 6.99996C12.8333 6.23392 12.6825 5.47537 12.3893 4.76764C12.0961 4.05991 11.6665 3.41685 11.1248 2.87517C10.5831 2.33349 9.94005 1.90381 9.23232 1.61066C8.52459 1.31751 7.76604 1.16663 7 1.16663V2.33329C8.23768 2.33329 9.42466 2.82496 10.2998 3.70013C11.175 4.5753 11.6667 5.76228 11.6667 6.99996Z" fill="#969BA3"/>
+</svg>

+ 4 - 3
src/components/pages/classroomObservation/components/analysisItem.vue

@@ -500,7 +500,7 @@ export default {
                 _copyData.jsonData
               );
             }
-            this.changeShowIndex(1);
+            this.changeShowIndex(1,false);
             this.loading = false;
             this.$nextTick(() => {
               if (
@@ -586,7 +586,7 @@ export default {
           console.log("取消");
         });
     },
-    changeShowIndex(value) {
+    changeShowIndex(value,save=true) {
       if (this.historyResult.length == 0) return;
       if (value == -1) {
         if (this.showIndex > 0) this.showIndex--;
@@ -602,7 +602,8 @@ export default {
       if (JSON.stringify(_copyData) == JSON.stringify(_oldCopyDate)) return;
       // this.data = _copyData;
       this.$emit("editItem", this.data.id, _copyData);
-      this.$emit("saveItem", this.data.id, _copyData);
+      console.log("save👉",save)
+      if(save)this.$emit("saveItem", this.data.id, _copyData);
     },
     // editTitle(){
     // 	this.$refs.editNameDialogRef.open(this.data.jsonData.anotherName?this.data.jsonData.anotherName:this.data.jsonData.name)

+ 5 - 5
src/components/pages/classroomObservation/components/analysisSpecialItem.vue

@@ -832,7 +832,7 @@ CH:${_CH}
               _copyData.jsonData
             );
           }
-          this.changeShowIndex(1);
+          this.changeShowIndex(1,false);
           this.loading = false;
 					this.$nextTick(()=>{
 
@@ -858,7 +858,7 @@ CH:${_CH}
           console.log("取消");
         });
     },
-    changeShowIndex(value) {
+    changeShowIndex(value,save=true) {
       if (this.historyResult.length == 0) return;
       if (value == -1) {
         if (this.showIndex > 0) this.showIndex--;
@@ -874,7 +874,8 @@ CH:${_CH}
       if (JSON.stringify(_copyData) == JSON.stringify(_oldCopyDate)) return;
       // this.data = _copyData;
       this.$emit("editItem", this.data.id, _copyData);
-      this.$emit("saveItem", this.data.id, _copyData);
+      console.log("save👉",save)
+      if(save)this.$emit("saveItem", this.data.id, _copyData);
     },
     convertToSeconds(time) {
       let parts = time.split(":");
@@ -1128,10 +1129,9 @@ CH:${_CH}
                 _copyData.jsonData
               );
             }
-            this.changeShowIndex(1);
+            this.changeShowIndex(1,false);
             this.loading = false;
 						this.$nextTick(()=>{
-
 							this.editEcharts(true);
 						})
           })

+ 561 - 39
src/components/pages/classroomObservation/dialog/batchCreationClassDialog.vue

@@ -47,7 +47,7 @@
                     i =>
                       selectStatus == "99" ||
                       statusList
-                        .find(i => i.value == selectStatus)
+                        .find(i => i.value === selectStatus)
                         .allow.includes(i.state)
                   ).length
                 }}</span
@@ -82,6 +82,7 @@
               @changeChecked="changeCardChecked"
               @editBaseMessage="editBaseMessage"
               @changeData="changeData"
+              @taskBtn="taskBtn"
             />
           </div>
         </div>
@@ -103,7 +104,9 @@ import batchClassCard from "../newComponents/batchClassCard.vue";
 import uploadFileToCreateClassDialog from "./uploadFileToCreateClassDialog.vue";
 import editBaseMessageDialog from "./editBaseMessageDialog.vue";
 import { v4 as uuidv4 } from "uuid";
+import { toolMixin } from "../tools/mixin";
 export default {
+  mixins: [toolMixin],
   components: {
     batchClassCard,
     uploadFileToCreateClassDialog,
@@ -116,13 +119,15 @@ export default {
         { label: "已完成", value: "2", allow: ["2"] },
         { label: "处理中", value: "1", allow: ["1"] },
         { label: "等待处理", value: "0", allow: ["0"] },
-        { label: "停止中",value:"3",allow:['3']}
+        { label: "待开始", value: "3", allow: ["3"] }
       ],
       userId: this.$route.query["userid"],
       selectStatus: "99",
       show: false,
       selectList: [],
-      dataList: []
+      dataList: [],
+      nowDoTaskId: [],
+      dialogTagDataList: []
     };
   },
   computed: {
@@ -227,6 +232,8 @@ export default {
           { value: 1, name: "学科课堂分析", loading: false },
           { value: 2, name: "扩展分析", loading: false }
         ];
+      }else{
+        tagList = tagList.dialogTagList;
       }
 
       let batch = uuidv4();
@@ -260,6 +267,7 @@ export default {
                 fileList1: [],
                 fileList2: [],
                 fileList3: [],
+                name:"课堂记录",
                 NephogramList: [],
                 videoList: []
               }
@@ -295,6 +303,12 @@ export default {
               text: "生成报告",
               status: "0",
               progress: "0"
+            },
+            {
+              type: "createClass",
+              text: "创建课堂",
+              status: "0",
+              progress: "0"
             }
           ];
         } else if (i.type == "audio/wav") {
@@ -317,25 +331,39 @@ export default {
               text: "文本转录",
               status: "0",
               progress: "0"
-            },
-            {
+            }
+          ];
+
+          if (data.json.automaticCoding) {
+            data.jsonData.steps.push({
               type: "automaticCoding",
               text: "自动编码",
               status: "0",
               progress: "0"
-            },
-            {
-              type: "getFileIds",
-              text: "获取文件fileid",
-              status: "0"
-            },
-            {
-              type: "generateReport",
-              text: "生成报告",
-              status: "0",
-              progress: "0"
-            }
-          ];
+            });
+          }
+
+          data.jsonData.steps.push(
+            ...[
+              {
+                type: "getFileIds",
+                text: "获取文件fileid",
+                status: "0"
+              },
+              {
+                type: "generateReport",
+                text: "生成报告",
+                status: "0",
+                progress: "0"
+              },
+              {
+                type: "createClass",
+                text: "创建课堂",
+                status: "0",
+                progress: "0"
+              }
+            ]
+          );
         } else if (i.type == "video/mp4") {
           data.jsonData.baseMessage.imageList.videoList = [
             {
@@ -362,29 +390,44 @@ export default {
               text: "文本转录",
               status: "0",
               progress: "0"
-            },
-            {
+            }
+          ];
+          if (data.jsonData.automaticCoding) {
+            data.jsonData.steps.push({
               type: "automaticCoding",
               text: "自动编码",
               status: "0",
               progress: "0"
-            },
-            {
-              type: "getFileIds",
-              text: "获取文件fileid",
-              status: "0"
-            },
-            {
-              type: "generateReport",
-              text: "生成报告",
-              status: "0",
-              progress: "0"
-            }
-          ];
+            });
+          }
+          data.jsonData.steps.push(
+            ...[
+              {
+                type: "getFileIds",
+                text: "获取文件fileid",
+                status: "0"
+              },
+              {
+                type: "generateReport",
+                text: "生成报告",
+                status: "0",
+                progress: "0"
+              },
+              {
+                type: "createClass",
+                text: "创建课堂",
+                status: "0",
+                progress: "0"
+              }
+            ]
+          );
         }
 
         promiseList.push(
           new Promise((resolve, reject) => {
+            // 本地保存fileObj
+            const fileObj = data.jsonData.fileData.fileObj;
+            delete data.jsonData.fileData.fileObj;
             const params = [
               {
                 remarks: data.remarks,
@@ -401,6 +444,7 @@ export default {
               .then(res => {
                 const _data = res.data[0][0];
                 if (_data.id) {
+                  data.jsonData.fileData.fileObj = fileObj;
                   data.id = _data.id;
                   this.dataList.push(data);
                 }
@@ -527,19 +571,46 @@ export default {
           }
         });
     },
+    //获取所有的模块分析
+    getDialogTagDataList() {
+      let params = {
+        uid: this.userId
+      };
+      this.ajax
+        .get(this.$store.state.api + "select_smodel", params)
+        .then(res => {
+          let _result = res.data[0];
+          this.dialogTagDataList = _result;
+        })
+        .catch(e => {
+          console.log(e);
+          this.$message.error("获取模块分析列表失败");
+        });
+    },
     updateTask(id) {
       return new Promise((resolve, reject) => {
         let _data = this.dataList.find(i => i.id === id);
         if (_data) {
+          const dataCopy = JSON.parse(JSON.stringify(_data));
+          if (dataCopy.jsonData.fileData.fileObj) {
+            delete _data.jsonData.fileData.fileObj;
+          }
+          if (dataCopy.jsonData.baseMessage.editorBarData && dataCopy.jsonData.baseMessage.editorBarData.content) {
+            delete dataCopy.jsonData.baseMessage.editorBarData.content;
+          }
+
+          console.log("dataCopy", dataCopy);
           let params = [
             {
-              id: _data.id,
+              id: dataCopy.id,
               userId: this.userId,
-              remarks: _data.remarks,
-              status: _data.status,
-              json: JSON.stringify(_data.jsonData),
-              createId: _data.createId,
-              batch: _data.batch
+              remarks: dataCopy.remarks,
+              status: ["0", "1"].includes(dataCopy.status)
+                ? "3"
+                : dataCopy.status,
+              json: JSON.stringify(dataCopy.jsonData),
+              createId: dataCopy.createId,
+              batch: dataCopy.batch
             }
           ];
 
@@ -570,10 +641,461 @@ export default {
           this.updateTask(this.dataList[_index].id);
         }
       }
+    },
+    taskBtn(obj) {
+      let { type, id } = obj;
+      if (type === "startTask" && id) {
+        // this.startTask(id);
+        if (
+          this.dataList.some(i => i.status === "1") &&
+          this.dataList.find(i => i.id === id).status === "0"
+        ) {
+          this.$confirm(
+            "您确定要开始该任务嘛?其他已开始的任务会暂停。",
+            "提示",
+            {
+              confirmButtonText: "确定",
+              cancelButtonText: "取消",
+              type: "warning"
+            }
+          )
+            .then(() => {
+              this.startTask(id);
+            })
+            .catch(() => {
+              console.log("不暂停");
+            });
+        } else {
+          this.startTask(id);
+        }
+      } else if (type === "stopTask" && id) {
+        this.$confirm("您确定要停止该任务吗?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        })
+          .then(() => {
+            this.stopTask(id);
+          })
+          .catch(() => {
+            console.log("不暂停");
+          });
+      } else if (type === "pauseTask" && id) {
+        this.$confirm("您确定要暂停该任务吗?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        })
+          .then(() => {
+            this.pauseTask(id);
+          })
+          .catch(() => {
+            console.log("不暂停");
+          });
+      }
+    },
+    async startTask(id) {
+      let _isStartTaskIndex = this.dataList.findIndex(i => i.status === "1");
+      let _needStartTaskIndex = this.dataList.findIndex(i => i.id === id);
+      if (_isStartTaskIndex === -1) {
+        //没有任务在进行,直接开始处理
+        this.dataList[_needStartTaskIndex].status = "1"; //处理中
+      } else if (
+        this.dataList[_needStartTaskIndex].status === "3" &&
+        _isStartTaskIndex !== -1
+      ) {
+        //有任务在进行,且这个任务是从待开始状态到开始状态,等待处理
+        this.dataList[_needStartTaskIndex].status = "0";
+      } else if (
+        _isStartTaskIndex !== -1 &&
+        this.dataList[_needStartTaskIndex].status === "0"
+      ) {
+        //有任务在进行,且这个任务是从等待状态到开始状态,停止现任务,开始新任务
+        this.nowDoTaskId = this.nowDoTaskId.filter(
+          i => i !== this.dataList[_isStartTaskIndex].id
+        );
+        this.dataList[_isStartTaskIndex].status = "0"; //
+        this.dataList[_needStartTaskIndex].status = "1"; //处理中
+      }
+
+      if (
+        !this.nowDoTaskId.includes(this.dataList.find(i => i.status === "1").id)
+      ) {
+        let _startData = JSON.parse(
+          JSON.stringify(this.dataList.find(i => i.status === "1"))
+        );
+
+        if (
+          this.dataList.find(i => i.id === _startData.id).jsonData.fileData
+            .fileObj
+        ) {
+          _startData.jsonData.fileData.fileObj = this.dataList.find(
+            i => i.id === _startData.id
+          ).jsonData.fileData.fileObj;
+        }
+        this.nowDoTaskId.push(_startData.id);
+        let _stepList = _startData.jsonData.steps;
+        for (let i = 0; i < _stepList.length; i++) {
+          //按顺序处理任务
+          let _step = _stepList[i];
+          console.log(_step);
+          if (_step.status === "1") continue;
+          if (_step.type === "uploadFile") continue;
+          if (_step.type === "getVideoVoice") {
+            //视频提取音频
+            _stepList[i].status = "2";
+            this.dataList.find(
+              i => i.id === _startData.id
+            ).jsonData.steps = _stepList;
+            let _fileData = _startData.jsonData.fileData;
+            console.log("👉", _fileData);
+            let audioFile = await this.getVideoToVoiceAndUploadMixin(_fileData);
+            console.log("👉", audioFile);
+            _startData.jsonData.fileData.videoUrl = _fileData.url;
+            _startData.jsonData.fileData.url = audioFile.Location;
+            _startData.jsonData.baseMessage.imageList.fileList = [
+              {
+                name: _fileData.name,
+                status: "success",
+                url: audioFile.Location,
+                uid: "1"
+              }
+            ];
+            _stepList[i].status = "1";
+            this.dataList.find(i => i.id === _startData.id).jsonData =
+              _startData.jsonData;
+            this.updateTask(_startData.id);
+            _startData.jsonData = JSON.parse(
+              JSON.stringify(
+                this.dataList.find(i => i.id === _startData.id).jsonData
+              )
+            );
+            // console.log(`${_startData.id}:已完成视频转音频`);
+          } else if (_step.type === "transcription") {
+            //文本转录
+            const fileData = _startData.jsonData.fileData;
+            if (fileData.type === "text/plain") {
+              //txt文件
+              _stepList[i].status = "2";
+              this.dataList.find(
+                i => i.id === _startData.id
+              ).jsonData.steps = _stepList;
+              let { editorBarData } = await this.getTextContentMixin(fileData);
+              this.dataList.find(
+                i => i.id === _startData.id
+              ).jsonData.baseMessage.editorBarData = editorBarData;
+              _stepList[i].status = "1";
+              this.dataList.find(
+                i => i.id === _startData.id
+              ).jsonData.steps = _stepList;
+              this.updateTask(_startData.id);
+              _startData.jsonData = JSON.parse(
+                JSON.stringify(
+                  this.dataList.find(i => i.id === _startData.id).jsonData
+                )
+              );
+              console.log(`${_startData.id}:已获取转录文稿(txt)`);
+            } else if (
+              fileData.type === "video/mp4" ||
+              fileData.type === "audio/wav"
+            ) {
+              //mp4与wav文件
+              _stepList[i].status = "2";
+              this.dataList.find(
+                i => i.id === _startData.id
+              ).jsonData.steps = _stepList;
+              // let { editorBarData } = await this.getTextContentMixin(fileData);
+              this.dataList.find(
+                i => i.id === _startData.id
+              ).jsonData.baseMessage.editorBarData = {
+                content: "xxxxxx",
+                url: "xxxxxxx"
+              };
+              _stepList[i].status = "1";
+              this.dataList.find(
+                i => i.id === _startData.id
+              ).jsonData.steps = _stepList;
+              this.updateTask(_startData.id);
+              _startData.jsonData = JSON.parse(
+                JSON.stringify(
+                  this.dataList.find(i => i.id === _startData.id).jsonData
+                )
+              );
+              console.log(`${_startData.id}:已获取转录文稿(mp4/wav)`);
+            }
+          } else if (_step.type === "automaticCoding") {
+            if (_startData.jsonData.automaticCoding) {
+              console.log("开始自动编码");
+            } else {
+              _stepList[i].status = "1";
+              this.dataList.find(
+                i => i.id === _startData.id
+              ).jsonData.steps = _stepList;
+              this.updateTask(_startData.id);
+              _startData.jsonData = JSON.parse(
+                JSON.stringify(
+                  this.dataList.find(i => i.id === _startData.id).jsonData
+                )
+              );
+            }
+          } else if (_step.type === "getFileIds") {
+            //文件获取fileId
+            _stepList[i].status = "2";
+            this.dataList.find(
+              i => i.id === _startData.id
+            ).jsonData.steps = _stepList;
+            let _fileData = _startData.jsonData.fileData;
+            let { fileId } = await this.getFileIdMixin(_fileData.url);
+            this.dataList.find(
+              i => i.id === _startData.id
+            ).jsonData.file_ids = fileId;
+            _stepList[i].status = "1";
+            this.dataList.find(
+              i => i.id === _startData.id
+            ).jsonData.steps = _stepList;
+            this.updateTask(_startData.id);
+            _startData.jsonData = JSON.parse(
+              JSON.stringify(
+                this.dataList.find(i => i.id === _startData.id).jsonData
+              )
+            );
+            console.log(`${_startData.id}:已获取fileId`);
+          } else if (_step.type === "generateReport") {
+            //生成报告
+            _stepList[i].status = "2";
+            this.dataList.find(
+              i => i.id === _startData.id
+            ).jsonData.steps = _stepList;
+            let _analysisList = _startData.jsonData.analysisList;
+
+            let promises = [];
+            let _content =
+              _startData.jsonData.baseMessage.editorBarData.content;
+            if (!_content) {
+              _content = await this.getFile(
+                _startData.jsonData.baseMessage.editorBarData.url
+              );
+              _content = _content.data;
+              _startData.jsonData.baseMessage.editorBarData.content = _content;
+            }
+            promises = _analysisList.map((i, index) => {
+              return new Promise(async resolve => {
+                _startData.jsonData.analysisList[index].status = "default"; //默认状态
+                let _num = 0;
+                let _maxNum = 5;
+                const getAnalysis = async () => {
+                  if (
+                    ["tryAgainMax", "noAgentData"].includes(
+                      _startData.jsonData.analysisList[index].status
+                    )
+                  ) {
+                    return resolve(_startData.jsonData.analysisList[index]);
+                  }
+                  if (_num >= _maxNum) {
+                    _startData.jsonData.analysisList[index].status =
+                      "tryAgainMax"; //超过尝试次数
+                    return resolve();
+                  }
+                  _num += 1;
+                  let _assistantData =
+                    this.dialogTagDataList.find(
+                      i2 => i2.id == i.jsonData.mId
+                    ) ||
+                    this.dialogTagDataList.find(
+                      i2 => i2.name == i.jsonData.name
+                    );
+
+                  if (!_assistantData) {
+                    _startData.jsonData.analysisList[index].status =
+                      "noAgentData"; //无对应的智能体
+                    return resolve();
+                  }
+                  let data = await this.getAnalysisMixin({
+                    fileId: _startData.jsonData.file_ids,
+                    content: _content,
+                    analysisData: i.jsonData,
+                    assistantData: _assistantData,
+                    baseMessage: _startData.jsonData.baseMessage
+                  });
+                  if (data.data == 1) {
+                    if (_num < _maxNum) {
+                      //重试
+                      getAnalysis();
+                    }
+                  } else {
+                    _startData.jsonData.analysisList[index].status = "success";
+                    _startData.jsonData.analysisList[index].jsonData =
+                      data.data;
+                    resolve();
+                  }
+                };
+                getAnalysis();
+              });
+            });
+
+            await Promise.all(promises).then(() => {
+              console.log(`${_startData.id}:已完成分析获取`);
+              console.log(_startData.jsonData.analysisList)
+                _stepList[i].status = "1";
+              this.dataList.find(
+                i => i.id === _startData.id
+              ).jsonData.steps = _stepList;
+
+              this.updateTask(_startData.id);
+              _startData.jsonData = JSON.parse(
+                JSON.stringify(
+                  this.dataList.find(i => i.id === _startData.id).jsonData
+                )
+              );
+            });
+          } else if (_step.type === "createClass") {
+            //创建课堂
+            _stepList[i].status = "2";
+            this.dataList.find(
+              i => i.id === _startData.id
+            ).jsonData.steps = _stepList;
+
+            //创建课堂   赋值好fileid   替换创建后课堂的基础数据  继续下一个任务
+
+
+            let newOption = await this.createClassMixin(_startData.jsonData);
+
+            this.$emit("addNewCourseOption",newOption.data);
+            this.dataList.find(
+              i => i.id === _startData.id
+            ).jsonData.createId = newOption.tid;
+            _stepList[i].status = "1";
+            this.dataList.find(
+              i => i.id === _startData.id
+            ).jsonData.steps = _stepList;
+            this.dataList.find(
+              i => i.id === _startData.id
+            ).status = "2";
+            this.updateTask(_startData.id);
+            _startData.jsonData = JSON.parse(
+              JSON.stringify(
+                this.dataList.find(i => i.id === _startData.id).jsonData
+              )
+            );
+            console.log(`${_startData.id}:已创建课堂`);
+            // 查看是否有需要开启的任务
+            if(this.dataList.find(i=>i.status=='0')){
+              let id = this.dataList.find(i=>i.status=='0').id;
+              this.startTask(id);
+            }
+
+          //   let _analysisList = _startData.jsonData.analysisList;
+          //   let createJson = _analysisList.map(i=>{return {
+          //     jsonData: i.jsonData,
+          //     type: i.Type,
+          //     index: i.tIndex
+          //   }})
+          //   var OpenCC = require("opencc-js");
+          //   let converter = OpenCC.Converter({
+          //     from: "hk",
+          //     to: "cn"
+          //   });
+          //   createJson = createJson.filter(
+          //     i =>
+          //       !i.isOtherData &&
+          //       converter(i.jsonData.name) != converter("词频词汇分析")
+          //   );
+          //   let params = {
+          //     tid: uuidv4(),
+          //     userid: this.userId,
+          //     template: createJson
+          //   }
+          //   this.ajax
+          // .post(
+          //   "https://gpt4.cocorobo.cn/insert_classroom_observation_template",
+          //   params
+          // )
+          // .then(res => {
+          //   let _data = res.data.FunctionResponse;
+          //   if (converter(_data.message) == converter("创建成功")) {
+          //     this.ajax
+          //       .post("https://gpt4.cocorobo.cn/insert_classroom_observation", {
+          //         tid: params.tid,
+          //         type: 10,
+          //         index: 0,
+          //         json_data: JSON.stringify({ file_ids: _startData.jsonData.file_ids }),
+          //         userid: this.userId
+          //       })
+          //       .then(res2 => {
+          //         let _data2 = res2.data.FunctionResponse;
+          //         if (converter(_data2.message) == converter("创建成功")) {
+          //           let newOption = {id:uuidv4(),label:_startData.jsonData.baseMessage.name,value:params.tid}
+          //           console.log(newOption);
+
+          //           this.$emit("addNewCourseOption",newOption);
+          //           _stepList[i].status = "1";
+          //           this.dataList.find(
+          //             i => i.id === _startData.id
+          //           ).jsonData.steps = _stepList;
+          //           this.dataList.find(
+          //             i => i.id === _startData.id
+          //           ).status = "2";
+          //           this.updateTask(_startData.id);
+          //           _startData.jsonData = JSON.parse(
+          //             JSON.stringify(
+          //               this.dataList.find(i => i.id === _startData.id).jsonData
+          //             )
+          //           );
+          //           console.log(`${_startData.id}:已创建课堂`);
+
+          //           // 查看是否有需要开启的任务
+          //           if(this.dataList.find(i=>i.status=='0')){
+          //             let id = this.dataList.find(i=>i.status=='0').id;
+          //             this.startTask(id);
+          //           }
+          //         }
+          //       }).catch(err=>{
+          //         console.log("存储fileId失败")
+          //         console.log(err)
+          //       })
+          //   }
+          // }).catch(err=>{
+          //   console.log("创建课堂失败")
+          //   console.log(err)
+          // })
+
+
+
+
+          }
+        }
+      }
+    },
+    // 暂停任务
+    pauseTask(id) {
+      let _waitTask = this.dataList.find(i => i.status === "0");
+      if (_waitTask) {
+        //暂停这个任务,
+        this.dataList.find(i => i.id === id).status = "0";
+        // 开始另一个任务
+        this.startTask(_waitTask.id);
+      } else {
+        //没有任务了,所以改为待开始(停止)
+        this.dataList.find(i => i.id === id).status = "3";
+      }
+    },
+    //停止任务
+    stopTask(id) {
+      let _waitTask = this.dataList.find(i => i.status === "0");
+      if (_waitTask) {
+        //停止这个任务,
+        this.dataList.find(i => i.id === id).status = "3";
+        // 开始另一个任务
+        this.startTask(_waitTask.id);
+      } else {
+        //只停止这个任务
+        this.dataList.find(i => i.id === id).status = "3";
+      }
     }
   },
   mounted() {
     this.getTaskList();
+    this.getDialogTagDataList();
   }
 };
 </script>

+ 3 - 1
src/components/pages/classroomObservation/dialog/uploadFileToCreateClassDialog.vue

@@ -212,7 +212,8 @@ export default {
         name: _name,
         url: data.Location,
         type: _type,
-        size: size
+        size: size,
+        fileObj:this.fileList.find(i => i.index == res.index).fileObj,
       };
       this.fileList.find(i => i.index == res.index).status = "success";
       let uploadingFile = this.fileList.find(file => file.status === "wait");
@@ -247,6 +248,7 @@ export default {
               index: uuidv4(),
               successData: null,
               name: files[i].name,
+              fileObj:files[i],
               type: files[i].type,
               progress: { status: "", percent: 0, key: "", uploadid: "" },
               status: "wait"

+ 7 - 3
src/components/pages/classroomObservation/index.vue

@@ -83,10 +83,10 @@
       </div>
       <div class="co-h2-right">
 
-        <!--<div class="co-h2-r-btn" style="background: rgba(54, 129, 252, 1)" @click.stop="batchBtn()">
+        <div class="co-h2-r-btn" style="background: rgba(54, 129, 252, 1)" @click.stop="batchBtn()" v-show="false">
           <span class="co-h2-r-b-icon3"></span>
           <div style="color: #fff;">批量创建</div>
-        </div> -->
+        </div>
         <div
           :class="['co-h2-r-btn', fileId && tid ? '' : 'ca-h2-r-noActive']"
           style="background: rgba(54, 129, 252, 1)"
@@ -206,7 +206,7 @@
       ref="changeCourseNameDialogRef"
       @success="changeCourseSuccess"
     />
-    <batchCreationClassDialog ref="batchCreationClassDialogRef"/>
+    <batchCreationClassDialog ref="batchCreationClassDialogRef" @addNewCourseOption="addNewCourseOption"/>
 
     <!-- <addNewCourseDialog
 			:courseList="optionData"
@@ -388,6 +388,7 @@ export default {
           userid: this.userId,
           template: json
         };
+        console.log("创建新课堂",params);
         this.ajax
           .post(
             "https://gpt4.cocorobo.cn/insert_classroom_observation_template",
@@ -1214,6 +1215,9 @@ export default {
     batchBtn(){
       this.$refs.batchCreationClassDialogRef.open();
     },
+    addNewCourseOption(newOption){
+      this.optionData.unshift(newOption);
+    },
   },
   mounted() {
     this.getCourseList().then(_ => {

+ 170 - 24
src/components/pages/classroomObservation/newComponents/batchClassCard.vue

@@ -8,15 +8,15 @@
         <div class="bcc_r_t_left">
           <div class="bcc_r_t_l_image">
             <img
-              v-if="cardData.jsonData.fileData.type=='text/plain'"
+              v-if="cardData.jsonData.fileData.type == 'text/plain'"
               src="../../../../assets/icon/classroomObservation/file_icon.svg"
             />
             <img
-              v-if="cardData.jsonData.fileData.type=='audio/wav'"
+              v-if="cardData.jsonData.fileData.type == 'audio/wav'"
               src="../../../../assets/icon/classroomObservation/audio_file.svg"
             />
             <img
-              v-if="cardData.jsonData.fileData.type=='video/mp4'"
+              v-if="cardData.jsonData.fileData.type == 'video/mp4'"
               src="../../../../assets/icon/classroomObservation/videoFile_icon.svg"
             />
           </div>
@@ -24,6 +24,7 @@
             <div>
               <span>{{ cardData.jsonData.baseMessage.courseName }}</span>
               <img
+                v-show="!cardData.status=='2'"
                 src="../../../../assets/icon/classroomObservation/table_edit.svg"
                 @click="editBaseMessage"
               />
@@ -32,12 +33,54 @@
           </div>
         </div>
         <div class="bcc_r_t_right">
-          <span class="status_wait" v-if="cardData.status == '3'">停止中</span>
+          <span class="status_wait" v-if="cardData.status == '3'">待开始</span>
           <span class="status_fail" v-if="cardData.status == '4'">失败</span>
           <span class="status_success" v-if="cardData.status == '2'"
             >已完成</span
           >
-          <span class="status_doing" v-if="cardData.status == '1'">处理中</span>
+          <span class="status_doing" v-if="cardData.status == '1'">
+            <span>处理中</span>
+            <div class="stepBox">
+              <div
+                class="sb_item"
+                v-for="(item, index) in cardData.jsonData.steps"
+                :key="index"
+              >
+                <!-- 1完成 -->
+                <img
+                  src="../../../../assets/icon/classroomObservation/successStatus_icon.svg"
+                  v-if="item.status==='1'"
+                />
+
+
+                <!-- 0等待 -->
+                <img
+                  class="rotation"
+                  src="../../../../assets/icon/classroomObservation/waitStatus_icon.svg"
+                  v-if="item.status==='0'"
+                />
+
+
+                <!-- 2处理中 -->
+                <img
+                  class="rotation"
+                  src="../../../../assets/icon/classroomObservation/isDoStatus_icon.svg"
+                  v-if="item.status==='2'"
+                />
+                <div>{{ item.text }}</div>
+                <span>
+                  <span
+                    v-if="
+                      item.status == '2' &&
+                        item.progress &&
+                        item.progress !== '0'
+                    "
+                    >{{ item.progress }}%</span
+                  ></span
+                >
+              </div>
+            </div>
+          </span>
           <span class="status_wait" v-if="cardData.status == '0'"
             >等待处理</span
           >
@@ -45,21 +88,50 @@
       </div>
       <div class="bcc_r_bottom">
         <div class="bcc_r_b_left">
-          <el-input placeholder="备注" v-model="cardData.remarks" @change="changeRemarks"></el-input>
+          <el-input
+            placeholder="备注"
+            v-model="cardData.remarks"
+            @change="changeRemarks"
+          ></el-input>
         </div>
         <div class="bcc_r_b_right">
           <el-button
             size="small"
             @click="goToEdit"
-            v-if="[2].includes(cardData.status)"
+            v-if="['2'].includes(cardData.status)"
             >前往编辑</el-button
           >
-          <!-- <el-button size="small" @click="lookReport">查看报告</el-button> -->
           <el-button
+            size="small"
+            @click="lookReport"
+            v-if="['2'].includes(cardData.status)"
+            >查看报告</el-button
+          >
+          <!-- <el-button
             size="small"
             @click="regenerate"
-            v-if="[2, 3].includes(cardData.status)"
+            v-if="['2', '3'].includes(cardData.status)"
             >重新生成</el-button
+          > -->
+          <el-button
+            size="small"
+            type="primary"
+            v-if="['3', '0'].includes(cardData.status)"
+            @click="start"
+            >开始</el-button
+          >
+          <el-button
+            size="small"
+            v-if="['1'].includes(cardData.status)"
+            @click="pause"
+            >暂停</el-button
+          >
+          <el-button
+            size="small"
+            v-if="['0', '1'].includes(cardData.status)"
+            type="danger"
+            @click="stop"
+            >停止</el-button
           >
         </div>
       </div>
@@ -76,10 +148,10 @@ export default {
         return {};
       }
     },
-    isSelect:{
-      type:Boolean,
-      default:false
-    },
+    isSelect: {
+      type: Boolean,
+      default: false
+    }
   },
   data() {
     return {
@@ -152,7 +224,7 @@ export default {
     };
   },
   watch: {
-    isSelect(newValue){
+    isSelect(newValue) {
       this.checked = newValue;
     },
     // checked(newValue) {
@@ -167,10 +239,10 @@ export default {
       handler(newValue) {
         if (newValue) {
           this.cardData = JSON.parse(JSON.stringify(newValue));
-          this.$forceUpdate()
+          this.$forceUpdate();
         }
       }
-    },
+    }
     // cardData(newValue) {
     //   if (JSON.stringify(this.data) != JSON.stringify(newValue)) {
     //     this.$emit("changeData", {});
@@ -179,7 +251,7 @@ export default {
   },
   methods: {
     editBaseMessage() {
-      this.$emit("editBaseMessage",this.cardData.id);
+      this.$emit("editBaseMessage", this.cardData.id);
     },
     //前往编辑
     goToEdit() {
@@ -193,18 +265,27 @@ export default {
     regenerate() {
       this.$message.info("重新生成");
     },
-    changeRemarks(newValue){
-      if(this.data.remarks !=newValue){
-        this.$emit("changeData",{field:['remarks'],data:this.cardData})
+    changeRemarks(newValue) {
+      if (this.data.remarks != newValue) {
+        this.$emit("changeData", { field: ["remarks"], data: this.cardData });
       }
     },
-    changeChecked(newValue){
-      if (newValue && newValue!=this.isSelect) {
-        this.$emit("changeChecked", {type:0,id:this.cardData.id});
+    changeChecked(newValue) {
+      if (newValue && newValue != this.isSelect) {
+        this.$emit("changeChecked", { type: 0, id: this.cardData.id });
       } else {
-        this.$emit("changeChecked", {type:1,id:this.cardData.id});
+        this.$emit("changeChecked", { type: 1, id: this.cardData.id });
       }
     },
+    start() {
+      this.$emit("taskBtn", { type: "startTask", id: this.cardData.id });
+    },
+    stop() {
+      this.$emit("taskBtn", { type: "stopTask", id: this.cardData.id });
+    },
+    pause() {
+      this.$emit("taskBtn", { type: "pauseTask", id: this.cardData.id });
+    }
   },
   mounted() {
     if (this.data) {
@@ -281,6 +362,58 @@ export default {
 
 .bcc_r_t_right > span {
   font-size: 16px;
+  display: block;
+  position: relative;
+}
+
+.stepBox {
+  width: 200px;
+  height: auto;
+  background-color: #fff;
+  position: absolute;
+  left: calc(100% + 22px);
+  top: -21px;
+  box-sizing: border-box;
+  border: 1px solid #d9d9d9;
+  border-radius: 12px;
+  box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.05);
+  color: #000;
+  padding: 10px 10px;
+  cursor: default;
+}
+
+.sb_item {
+  width: 100%;
+  height: 25px;
+  display: flex;
+  align-items: center;
+  justify-content: space-around;
+}
+
+.sb_item > img {
+  width: 20px;
+  height: 20px;
+}
+
+.sb_item > div {
+  max-width: calc(100% - 20px - 35px - 15px);
+  width: calc(100% - 20px - 35px - 15px);
+  height: 100%;
+  margin: 0 5px 0 10px;
+  display: block;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  line-height: 24px;
+}
+
+.sb_item > span {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 35px;
+  height: 100%;
+  color: rgba(54, 129, 252, 1);
 }
 
 .bcc_r_t_l_message {
@@ -381,4 +514,17 @@ export default {
 .status_fail {
   color: rgb(185, 2, 2);
 }
+
+.rotation {
+  animation: rotate 4s linear infinite;
+}
+
+@keyframes rotate {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
 </style>

+ 1211 - 0
src/components/pages/classroomObservation/tools/mixin.js

@@ -0,0 +1,1211 @@
+import {
+  v4 as uuidv4
+} from 'uuid';
+
+const getFileBody = (url) => {
+  return new Promise((resolve, reject) => {
+    var credentials = {
+      accessKeyId: "AKIATLPEDU37QV5CHLMH",
+      secretAccessKey: "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",
+    }; //秘钥形式的登录上传
+    window.AWS.config.update(credentials);
+    window.AWS.config.region = "cn-northwest-1"; //设置区域
+    let url2 = url;
+    let _url2 = "";
+    if (
+      url2.indexOf("https://view.officeapps.live.com/op/view.aspx?src=") != -1
+    ) {
+      _url2 = url2.split(
+        "https://view.officeapps.live.com/op/view.aspx?src="
+      )[1];
+    } else {
+      _url2 = url2;
+    }
+    var s3 = new window.AWS.S3({ params: { Bucket: "ccrb" } });
+    let name = decodeURIComponent(_url2.split("https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/")[1])
+    var params = {
+      Bucket: "ccrb",
+      Key: name
+    };
+    s3.getObject(params, function (err, data) {
+      if (err) {
+        console.log(err, err.stack)
+        resolve({ data: 1 });
+      } else {
+        resolve({ data: data.Body });
+        console.log(data);
+      }          // sxuccessful response
+
+    });
+  });
+};
+
+var OpenCC = require("opencc-js");
+
+let converter = OpenCC.Converter({
+  from: "hk",
+  to: "cn"
+});
+
+import _ from "lodash";
+import Papa from "papaparse";
+import markdownIt from "markdown-it";
+
+export const toolMixin = {
+  methods: {
+    test() {
+      this.$message.info("测试")
+    },
+    getTextContentMixin(file) {
+      return new Promise((resolve) => {
+        const txtRegex = /\.(txt|csv)$/i;
+        if (txtRegex.test(file.url)) {
+          this.getFile(file.url).then(fileData => {
+            const arr = Papa.parse(fileData.data, {
+              header: false
+            }).data.slice(1);
+            // console.log(arr)
+            const _editorBarDataContent = `<table
+border="0"
+width="100%"
+cellpadding="0"
+cellspacing="0"
+style="text-align: center">
+<tbody>
+<tr>
+  <th>序号</th>
+  <th>开始时间</th>
+  <th>结束时间</th>
+  <th>发言内容</th>
+  <th>时长</th>
+  <th>说话人身份</th>
+  <th>行为编码</th>
+</tr>
+${arr.map(row => `<tr>
+  <td>${_.get(row, 0, "")}</td>
+  <td>${_.get(row, 1, "")}</td>
+  <td>${_.get(row, 2, "")}</td>
+  <td>${_.get(row, 3, "")}</td>
+  <td>${_.get(row, 4, "")}</td>
+  <td>${_.get(row, 5, "")}</td>
+  <td>${_.get(row, 6, "")}</td>
+</tr>
+`).join("\n")}</tbody></table>`;
+
+            var blob = new Blob([_editorBarDataContent], { type: "text/plain;charset=utf-8" });
+            blob.lastModifiedDate = new Date();
+            blob.name = `${file.name.replace('.txt', '')}_classroomObservation.txt`;
+            this.uploadFileMixin(blob).then(upload => {
+              resolve({ editorBarData: { type: "0", url: upload.Location, content: _editorBarDataContent } })
+              // this.ajax
+              //   .put("https://gpt4.cocorobo.cn/upload_file_knowledge", {
+              //     url: upload.Location
+              //   })
+              //   .then(res => {
+              //     let resData = res.data.FunctionResponse;
+              //     if (resData.result && resData.result.id) {
+              //       resolve({ fileId: resData.result.id, editorBarData: { type: "0", url: upload.Location }, })
+              //     }
+              //   })
+
+
+            })
+          })
+        }
+      })
+    },
+    uploadFileMixin(file) {
+      return new Promise((resolve, reject) => {
+        var credentials = {
+          accessKeyId: "AKIATLPEDU37QV5CHLMH",
+          secretAccessKey: "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"
+        }; //秘钥形式的登录上传
+        window.AWS.config.update(credentials);
+        window.AWS.config.region = "cn-northwest-1"; //设置区域
+
+        var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } }); //选择桶
+        var _this = this;
+
+        if (file) {
+          var params = {
+            Key:
+              file.name.split(".")[0] +
+              new Date().getTime() +
+              "." +
+              file.name.split(".")[file.name.split(".").length - 1],
+            ContentType: file.type,
+            Body: file,
+            "Access-Control-Allow-Credentials": "*",
+            ACL: "public-read"
+          }; //key可以设置为桶的相抵路径,Body为文件, ACL最好要设置
+          var options = {
+            partSize: 2048 * 1024 * 1024,
+            queueSize: 2,
+            leavePartsOnError: true
+          };
+          bucket
+            .upload(params, options)
+            .on("httpUploadProgress", function (evt) {
+              //这里可以写进度条
+              // _this.progressData.value = parseInt((evt.loaded * 100) / evt.total);
+              // console.log("Uploaded : " + parseInt((evt.loaded * 80) / evt.total) + '%');
+            })
+            .send(function (err, data) {
+              if (err) {
+                _this.$message.error("上传失败");
+              } else {
+                resolve(data);
+              }
+            });
+        }
+      })
+    },
+    getFileIdMixin(url) {
+      return new Promise((resolve) => {
+        this.ajax
+          .put("https://gpt4.cocorobo.cn/upload_file_knowledge", {
+            url: url
+          })
+          .then(res => {
+            let resData = res.data.FunctionResponse;
+            if (resData.result && resData.result.id) {
+              resolve({ fileId: resData.result.id })
+            }
+          })
+      })
+    },
+    getVideoToVoiceAndUploadMixin(fileData) {
+      return new Promise(async (resolve) => {
+        let _file = null;
+        console.log("fileData👉", fileData)
+        if (fileData.fileObj) {
+          _file = fileData.fileObj
+        } else if (fileData.url) {
+          let videoRes = await getFileBody(fileData.url);
+          if (videoRes.data === 1) return resolve({ data: 1 })
+          // 把uint8Array转换为视频文件
+          _file = new File([videoRes.data], 'video.mp4', { type: 'video/mp4' });
+        }
+        if (!_file) return resolve({ data: 0 })
+        console.log("需要处理的文件👉", _file)
+        try {
+          const reader = new FileReader();
+          reader.onload = async (e) => {
+            try {
+              // 创建音频上下文
+              const audioContext = new (window.AudioContext || window.webkitAudioContext)();
+
+              //解码音频数据
+              const buffer = await audioContext.decodeAudioData(e.target.result);
+
+              //创建离线音频上下文
+              const offlineAudioContext = new OfflineAudioContext({ numberOfChannels: buffer.numberOfChannels, length: buffer.length, sampleRate: buffer.sampleRate });
+
+              //创建音源节点
+              const source = offlineAudioContext.createBufferSource();
+              source.buffer = buffer;
+              source.connect(offlineAudioContext.destination);
+              source.start();
+
+              //渲染音频
+              const renderedBuffer = await offlineAudioContext.startRendering();
+              const wavBlob = this.bufferToWav(renderedBuffer);
+
+              // blob转成file文件
+              const audioFile = new File([wavBlob], 'audio.wav', { type: 'audio/wav' });
+              this.uploadFileMixin(audioFile).then(upload => {
+                resolve({ audioUrl: upload })
+              })
+            } catch (error) {
+              console.log("👉", error);
+              return resolve({ data: 2 })
+            }
+
+          }
+          reader.readAsArrayBuffer(_file);
+        } catch (error) {
+          console.log("👉", error);
+          return resolve({ data: 2 })
+        }
+      })
+    },
+    bufferToWav(audioBuffer) {
+      const numOfChan = audioBuffer.numberOfChannels;
+      const length = audioBuffer.length * numOfChan * 2;
+      const buffer = new ArrayBuffer(44 + length);
+      const view = new DataView(buffer);
+      const channels = [];
+      let pos = 0;
+      // 获取通道数据
+      for (let i = 0; i < audioBuffer.numberOfChannels; i++) {
+        channels.push(audioBuffer.getChannelData(i));
+      }
+      // 写入WAV头
+      this.writeUTFBytes(view, 0, 'RIFF');
+      view.setUint32(4, 44 + length - 8, true);
+      this.writeUTFBytes(view, 8, 'WAVE');
+      this.writeUTFBytes(view, 12, 'fmt ');
+      view.setUint32(16, 16, true);
+      view.setUint16(20, 1, true);
+      view.setUint16(22, numOfChan, true);
+      view.setUint32(24, audioBuffer.sampleRate, true);
+      view.setUint32(28, audioBuffer.sampleRate * 2 * numOfChan, true);
+      view.setUint16(32, numOfChan * 2, true);
+      view.setUint16(34, 16, true);
+      this.writeUTFBytes(view, 36, 'data');
+      view.setUint32(40, length, true);
+      // 写入PCM数据
+      pos = 44;
+      for (let i = 0; i < audioBuffer.length; i++) {
+        for (let j = 0; j < numOfChan; j++) {
+          const sample = Math.max(-1, Math.min(1, channels[j][i]));
+          view.setInt16(pos, sample < 0 ? sample * 0x8000 : sample * 0x7FFF, true);
+          pos += 2;
+        }
+      }
+      return new Blob([buffer], { type: 'audio/wav' });
+    },
+    writeUTFBytes(view, offset, string) {
+      for (let i = 0; i < string.length; i++) {
+        view.setUint8(offset + i, string.charCodeAt(i));
+      }
+    },
+    getFile(url) {
+      return new Promise((resolve, reject) => {
+        var credentials = {
+          accessKeyId: "AKIATLPEDU37QV5CHLMH",
+          secretAccessKey: "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"
+        }; //秘钥形式的登录上传
+        window.AWS.config.update(credentials);
+        window.AWS.config.region = "cn-northwest-1"; //设置区域
+        let url2 = url;
+        let _url2 = "";
+        if (
+          url2.indexOf("https://view.officeapps.live.com/op/view.aspx?src=") != -1
+        ) {
+          _url2 = url2.split(
+            "https://view.officeapps.live.com/op/view.aspx?src="
+          )[1];
+        } else {
+          _url2 = url2;
+        }
+        var s3 = new window.AWS.S3({ params: { Bucket: "ccrb" } });
+        let name = decodeURIComponent(
+          _url2.split("https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/")[1]
+        );
+        var params = {
+          Bucket: "ccrb",
+          Key: name
+        };
+        s3.getObject(params, function (err, data) {
+          if (err) {
+            console.log(err, err.stack);
+            resolve({ data: 1 });
+          } else {
+            const fileContent = data.Body.toString("utf-8");
+            resolve({ data: fileContent });
+          } // sxuccessful response
+        });
+        // axios({
+      });
+    },
+    getAnalysisMixin(obj) {
+      return new Promise(async (resolve) => {
+        let { fileId, assistantData, content, analysisData, baseMessage } = obj;
+        let type = 0;
+        let tips = ""
+        analysisData.mId = assistantData.id;
+        // console.log("处理数据👉", fileId, assistantData, content, analysisData, baseMessage)
+        if (['f8795150-699c-11ef-b873-005056b86db5', '01928d2b-699d-11ef-b873-005056b86db5', '069af7b9-699d-11ef-b873-005056b86db5', 'bfe844b1-7a45-11ef-9b30-005056b86db5'].includes(assistantData.id)) {//S-T分析:课堂时间分配   S-T分析:师生互动分析  S-T分析:教学模式分析 课堂活动光谱图
+          try {
+            let _result = [];
+            let _data = content;
+            let _div = document.createElement("div");
+            _div.innerHTML = _data;
+            let _tableRows = _div.querySelectorAll(`table tbody tr`);
+            _tableRows.forEach((i, index) => {
+              if (index == 0) return;
+              let obj = {
+                index: i.cells[0].textContent,
+                startTime: i.cells[1].textContent,
+                endTime: i.cells[2].textContent,
+                message: i.cells[3].textContent,
+                time: i.cells[4].textContent,
+                role: i.cells[5] ? i.cells[5].textContent : "",
+                behavior: i.cells[6] ? i.cells[6].textContent : ""
+              };
+              _result.push(obj);
+            });
+            if (_result.length == 0) return resolve({ data: 1, err: "未找到表格数据" });
+            if (assistantData.id == "f8795150-699c-11ef-b873-005056b86db5") {//课堂时间分配
+              let resultData = await this.getTimeAllocationDataMixin(_result, fileId)
+              if (resultData.message) analysisData.content = resultData.message;
+              if (resultData.eCharts) analysisData.eChartData = resultData.eCharts;
+              return resolve({ data: analysisData })
+            } else if (assistantData.id == "01928d2b-699d-11ef-b873-005056b86db5") {//师生互动分析
+              let resultData = await this.getInteractionAnalysisData(_result, fileId)
+              if (resultData.message) analysisData.content = resultData.message;
+              if (resultData.eCharts) analysisData.eChartData = resultData.eCharts;
+              return resolve({ data: analysisData })
+            } else if (assistantData.id == "069af7b9-699d-11ef-b873-005056b86db5") {//教学模式分析
+              let resultData = await this.getTeachingModeData(_result, fileId)
+              if (resultData.message) analysisData.content = resultData.message;
+              if (resultData.RT) analysisData.RT = resultData.RT;
+              if (resultData.CH) analysisData.CH = resultData.CH;
+              return resolve({ data: analysisData })
+            } else if (assistantData.id == "bfe844b1-7a45-11ef-9b30-005056b86db5") {//课堂活动光谱图
+              let resultData = await this.getSpectrogram(_result, fileId, content, assistantData)
+              if (resultData.message) analysisData.content = resultData.message;
+              if (resultData.eCharts) analysisData.getSpectrogram = resultData.eCharts;
+              return resolve({ data: analysisData })
+            }
+          } catch (error) {
+            return resolve({ data: 1, err: err })
+          }
+        } else {
+          let _msg = `使用文件检索的方式完整的去分析文件内容,并请完全按照要求输出。`;
+          if (assistantData.tips) {
+            tips = assistantData.tips;
+            type = 1;
+          } else if (assistantData.agentid) {
+            type = 0;
+          }
+          if (assistantData.id === '6b4a9650-48be-11ef-936b-12e77c4cb76b') {
+            _msg = `使用文件检索的方式完整的去分析文件内容,并基于以下的课堂基本内容,使用cpote课程设计模型改编一堂同主题的课程。
+课堂名称:${baseMessage.courseName}  搜课年级:${baseMessage.grade}  授课科目:${baseMessage.subject}`;
+          }
+          let params = {
+            id:
+              type == 0
+                ? assistantData.agentid
+                : "f8e1ebb2-2e0d-11ef-8bf4-12e77c4cb76b",
+            message: type == 0 ? _msg : tips,
+            session_name: uuidv4(),
+            userId: this.userId,
+            file_ids: fileId ? [fileId] : [],
+            model: "gpt-4o-2024-11-20",
+            sound_url: "",
+            temperature: 0.2,
+            top_p: 1,
+            max_completion_tokens: 4096,
+            stream: false,
+            uid: uuidv4()
+          };
+          this.ajax
+            .post("https://appapi.cocorobo.cn/api/agentchats/ai_agent_chat", params)
+            .then(async res => {
+              let _data = res.data;
+              analysisData.content = _data.message;
+              if (['1', '2', '3'].includes(assistantData.echartsType)) {
+                let echartsData = await this.getEChartsDataMixin(assistantData.echartsType, _data.message)
+                if (echartsData.data == 1) {
+                  console.log(`生成表格失败${echartsData.err}`)
+                  resolve({ data: analysisData })
+                } else {
+                  analysisData.eChartData = echartsData.data;
+                  resolve({ data: analysisData })
+                }
+              } else {
+                resolve({ data: analysisData })
+              }
+            })
+            .catch(err => {
+              resolve({ data: 1, err: err })
+            });
+        }
+      })
+    },
+    getContentTableMixin(content) {
+      return new Promise(resolve => {
+        let _content = content;
+        const md = new markdownIt();
+        let _contentHtml = md.render(_content);
+
+        let _contentTableList = [];
+        const rowRegex = /<tr[^>]*>([\s\S]*?)<\/tr>/g; // 匹配表格行,[\s\S] 匹配所有字符
+        const cellRegex = /<(th|td)[^>]*>([\s\S]*?)<\/\1>/g; // 匹配单元格,[\s\S] 匹配所有字符
+
+        let rowMatch;
+        while ((rowMatch = rowRegex.exec(_contentHtml)) !== null) {
+          const rowContent = rowMatch[1]; // 每一行的内容
+          const rowData = [];
+          let cellMatch;
+
+          // 匹配每个单元格 (th 或 td)
+          while ((cellMatch = cellRegex.exec(rowContent)) !== null) {
+            let _text = cellMatch[2].trim();
+            _text = _text.replace(/&[a-zA-Z]+;/g, "");
+            _text = _text.replace(/<\/?[^>]+(>|$)/g, "");
+            rowData.push(_text); // 将每个单元格的内容添加到当前行的数组中
+          }
+
+          // 如果该行有数据,推送到 _contentTableList 中
+          if (rowData.length) {
+            _contentTableList.push(rowData);
+          }
+        }
+
+        // 输出提取的表格数据
+
+        resolve(_contentTableList);
+      });
+    },
+    getEChartsDataMixin(type = "1", content) {
+      return new Promise((resolve) => {
+        if (type === "1") {
+          //词云图
+          return this.getContentTableMixin(content).then(res => {
+            try {
+              if (res.length <= 0) {
+                return resolve({ data: 0 })//未找到表格数据
+              }
+
+              let _result = [];
+              res.forEach((item, index) => {
+                if (index == 0) return; //去掉表头
+                let _valueItem = item[2] ? item[2] : item[1];
+                let _value = _valueItem.match(/(\d+)/);
+                _value = _value ? parseInt(_value[0]) : 0;
+                _result.push({
+                  value: _value,
+                  name: item[0],
+                  textStyle: { color: this.getRandomColorMixin() }
+                });
+              });
+
+              let _option = {
+                tooltip: {
+                  show: false
+                },
+                series: [
+                  {
+                    type: "wordCloud",
+                    sizeRange: [14, 38],
+                    rotationRange: [0, 0],
+                    keepAspect: false,
+                    shape: "circle",
+                    left: "center",
+                    top: "center",
+                    right: null,
+                    bottom: null,
+                    width: "100%",
+                    height: "100%",
+                    // rotationRange: [-90, 90],
+                    rotationStep: 20,
+                    data: _result
+                  }
+                ]
+              };
+              resolve({ data: _option })
+            } catch (e) {
+              resolve({ data: 1, err: e })
+            }
+          });
+        } else if (type == "2") {
+          //雷达图
+          //雷达图
+          return this.getContentTableMixin(content).then(res => {
+            try {
+              if (res.length <= 0) {
+                return resolve({ data: 0 })//未找到表格数据
+              }
+
+              let radarData = [];
+              let seriesData = { value: [] };
+
+              res.forEach((item, index) => {
+                if (index == 0) return; //去掉表头
+                radarData.push({ name: item[0], max: 5 });
+                let _valueItem = item[1] ? item[1] : "0";
+                let _value = _valueItem.match(/(\d+)/);
+                _value = _value ? parseInt(_value[0]) : 0;
+                seriesData.value.push(_value);
+              });
+
+              let _option = {
+                legend: {
+                  textStyle: {
+                    color: '#000'
+                  }
+                },
+                radar: {
+                  // shape: 'circle',
+                  indicator: radarData,
+                  name: {
+                    textStyle: {
+                      color: '#000'
+                    }
+                  }
+                },
+                series: [
+                  {
+                    type: "radar",
+                    data: [seriesData],
+                    label: {
+                      color: '#000'
+                    }
+                  }
+                ]
+              };
+              resolve({ data: _option })
+            } catch (e) {
+              resolve({ data: 1, err: e })
+            }
+          });
+        } else if (type == "3") {
+          //能量柱图
+          return this.getContentTableMixin(content).then(res => {
+            try {
+              if (res.length <= 0) {
+                return resolve({ data: 0 })//未找到表格数据
+              }
+
+              let _data = [];
+              let stepList = [];
+              stepList = this.calculateTopValuesMixin(res.length - 1);
+              res.forEach((item, index) => {
+                if (index == 0) return;
+                let _valueItem = item[1] ? item[1] : "0";
+                let _value = _valueItem.match(/(\d+)/);
+                _value = _value ? parseInt(_value[0]) : 0;
+                // 求百分比
+                _value = Math.floor((_value / 5).toFixed(2) * 100);
+                _data.push({
+                  value: _value,
+                  name: item[0],
+                  title: { offsetCenter: ["0%", `${stepList[index - 1]}%`] },
+                  detail: {
+                    valueAnimation: true,
+                    offsetCenter: ["0%", `${stepList[index - 1] + 15}%`]
+                  }
+                });
+              });
+
+              let _option = {
+                series: [
+                  {
+                    type: "gauge",
+                    startAngle: 90,
+                    endAngle: -270,
+                    pointer: {
+                      show: false
+                    },
+                    progress: {
+                      show: true,
+                      overlap: false,
+                      roundCap: true,
+                      clip: false,
+                      itemStyle: {
+                        borderWidth: 1,
+                        borderColor: "#464646"
+                      }
+                    },
+                    axisLine: {
+                      lineStyle: {
+                        width: 40
+                      }
+                    },
+                    splitLine: {
+                      show: false,
+                      distance: 0,
+                      length: 10
+                    },
+                    axisTick: {
+                      show: false
+                    },
+                    axisLabel: {
+                      show: false,
+                      distance: 50
+                    },
+                    data: _data,
+                    title: {
+                      fontSize: 14,
+                      color: "#000"
+                    },
+                    detail: {
+                      width: 50,
+                      height: 14,
+                      fontSize: 14,
+                      color: "#000",
+                      borderColor: "inherit",
+                      borderRadius: 20,
+                      borderWidth: 1,
+                      formatter: "{value}%"
+                    }
+                  }
+                ]
+              };
+              resolve({ data: _option })
+            } catch (e) {
+              resolve({ data: 1, err: e })
+            }
+          });
+        }
+      })
+    },
+    getRandomColorMixin() {
+      // 生成一个随机的 0 到 255 的数字,并将其转换为两位的十六进制形式
+      const randomHex = () => {
+        const hex = Math.floor(Math.random() * 256).toString(16);
+        return hex.length === 1 ? "0" + hex : hex; // 确保每个部分有两位
+      };
+
+      // 组合三种颜色(红、绿、蓝)的随机值
+      return `#${randomHex()}${randomHex()}${randomHex()}`;
+    },
+    calculateTopValuesMixin(len, minTop = -80, maxTop = 70, maxStep = 40) {
+      const length = len;
+      const middleIndex = Math.floor(length / 2); // 中间位置的索引
+      const totalRange = maxTop - minTop;
+      let step = totalRange / (length - 1); // 默认间隔
+
+      // 如果间隔大于 10%,则设置为最大 10%
+      if (step > maxStep) {
+        step = maxStep;
+      }
+
+      const topValues = [];
+
+      // 计算中间元素的top值
+      const middleTop = (minTop + maxTop) / 2;
+      topValues[middleIndex] = middleTop;
+
+      // 从中间向两边扩展,确保每个元素的top值
+      for (let i = middleIndex - 1; i >= 0; i--) {
+        topValues[i] = topValues[i + 1] - step; // 向上扩展
+      }
+
+      for (let i = middleIndex + 1; i < length; i++) {
+        topValues[i] = topValues[i - 1] + step; // 向下扩展
+      }
+
+      return topValues;
+    },
+    // 课堂时间分配
+    getTimeAllocationDataMixin(_dataList, fileId) {
+      return new Promise(async (resolve) => {
+        let _data = _dataList.reduce(
+          (pre, cur) => {
+            if (cur.role == "学生") {
+              pre[1].value += this.convertToSeconds(cur.time);
+            } else if (cur.role == "老师") {
+              pre[0].value += this.convertToSeconds(cur.time);
+            }
+            return pre;
+          },
+          [
+            { value: 0, name: "老师" },
+            { value: 0, name: "学生" }
+          ]
+        );
+        let _dataPercentage = JSON.parse(JSON.stringify(_data));
+        _data.forEach((i, index) => {
+          _dataPercentage[index].percentage =
+            (
+              (i.value / _data.reduce((pre, cur) => pre + cur.value, 0)) *
+              100
+            ).toFixed(2) + "%";
+        });
+
+        const _option = {
+          tooltip: {
+            left: "center",
+            trigger: "item",
+            formatter: "{a} <br/>{b}: {d}%",
+            textStyle: {
+              color: '#000000'
+            }
+          },
+          legend: {
+            top: "5%",
+            left: "center",
+            textStyle: {
+              color: '#000000'
+            }
+          },
+          series: [
+            {
+              name: "课堂时间分配",
+              type: "pie",
+              radius: ["40%", "70%"],
+              label: {
+                formatter: "{b}: {d}%",
+                color: '#000000'
+              },
+              emphasis: {
+                label: {
+                  show: true,
+                  formatter: "{b}: {d}%",
+                  color: '#000000'
+                },
+                itemStyle: {
+                  shadowBlur: 10,
+                  shadowOffsetX: 0,
+                  shadowColor: "rgba(0, 0, 0, 0.5)"
+                }
+              },
+              data: _data
+            }
+          ]
+        };
+
+        let _msg = `这是某一节课的师生时间占比,请你分析,写出结论,并给出指导建议。请使用3句完整的话,分析并给出建议。 请注意,当老师或学生的时间占比在【40~59%】之间的时候,也认为师生占比约为1:1,各占50%,师生时间占比比较均衡。
+  师生时间占比数据:
+  老师占比:${_dataPercentage[0].percentage}
+  学生占比:${_dataPercentage[1].percentage}
+  `;
+        let message = await this.getAiContentMixin({ _msg: _msg, fileId: fileId })
+
+        if (message.data == 1) {
+          return resolve({ eCharts: _option, message: "" })
+        } else {
+          return resolve({ eCharts: _option, message: message.data })
+        }
+
+      })
+      // return this.getAiContent(_msg);
+    },
+    // 师生互动分析
+    getInteractionAnalysisData(_dataList, fileId) {
+      return new Promise(async (resolve) => {
+        let _pushData = [0, 0];
+        let _result = [];
+        _dataList.forEach(i => {
+          if (i.role == "老师") {
+            _pushData[0] += this.convertToSeconds(i.time);
+          } else if (i.role == "学生") {
+            _pushData[1] += this.convertToSeconds(i.time);
+          }
+          return _result.push(JSON.parse(JSON.stringify(_pushData)));
+        });
+        let _flatArray = _result.flat();
+        const _max = Math.max(..._flatArray);
+        const _maxValue = Math.ceil(_max / 100) * 100;
+
+        const _option = {
+          xAxis: {
+            name: "老师", // X轴标题
+            nameLocation: "end", // 标题位置
+            scale: true,
+            min: 0,
+            max: _maxValue,
+            axisLabel: {
+              color: "#000" // 设置字体颜色为#000
+            },
+            nameTextStyle: {
+              color: "#000" // 设置老师字体颜色为#000
+            }
+          },
+          yAxis: {
+            name: "学生", // Y轴标题
+            nameLocation: "end", // 标题位置
+            scale: true,
+            min: 0,
+            max: _maxValue,
+            axisLabel: {
+              color: "#000" // 设置字体颜色为#000
+            },
+            nameTextStyle: {
+              color: "#000" // 设置学生字体颜色为#000
+            }
+          },
+          grid: {
+            containLabel: true
+          },
+          series: [
+            {
+              name: "数据",
+              step: "start",
+              data: _result,
+              type: "line",
+              lineStyle: {
+              }
+            },
+            {
+              name: "对角线",
+              type: "line",
+              data: [
+                [0, 0],
+                [_maxValue, _maxValue]
+              ],
+              lineStyle: {
+                type: "dashed",
+              },
+              markLine: {
+                symbol: ["none", "none"]
+              }
+            }
+          ]
+        };
+
+        let _msg = `
+  ## 任务
+  请你结合 FIAS 相关的知识,根据以下提供给你的课堂原始数据(包含S和t的数据),请你具体描述整个课堂S行为与T行为的持续性与变化性。比如,课堂一开始老师占比主导,大约5分钟之后,进入到学生为主的小组讨论环节。在整个课堂之中,老师与学生的互动比较频繁,老师会频繁询问学生问题,引导学生思考。之后是授课时间与问答时间。等等。
+  ## 输出要求 请使用自然语言进行描述,使用不超过5句完整的话进行整体性、概括性的描述,不要包含具体的时长信息。总结性概括之后,使用1句话对整个课堂的教师引导行为进行鼓励和评价,再使用1句话给出相应的优化建议。
+  ## 你的知识库 定义与目的:S-T图,即学生-教师(Student-Teacher)图,主要用于记录和分析课堂上的学生行为(S)与教师行为(T)的时间分布。这种图形能够帮助教育专家和教师可视化课堂互动的流程,从而判断课堂的教学型态,如练习型、对话型、讲授型或混合型。 绘制方法:S-T图的绘制开始于教学的起始时刻,纵轴表示学生行为(S),横轴表示教师行为(T)。实际课堂观察或录像回放中,按照固定时间间隔(通常每30秒)采样,将对应的行为按时间顺序标记在相应的轴上。通过这种方法,可以清晰看到课堂上教师行为与学生行为的交替模式及其随时间的变化。 应用场景:例如,一个典型的应用是在分析不同类型课堂活动时使用S-T图。在讲授型课堂中,教师行为的时间占比会较高,S-T图显示较长的横轴(T行为)延续;而在练习型或对话型课堂中,学生行为的时间占比增高,显示为较长的纵轴(S行为)。
+  ## 课堂实录
+  ${JSON.stringify(_dataList)}
+  `;
+
+        let message = await this.getAiContentMixin({ _msg: _msg, fileId: fileId })
+
+        if (message.data == 1) {
+          return resolve({ eCharts: _option, message: "" })
+        } else {
+          return resolve({ eCharts: _option, message: message.data })
+        }
+      })
+
+    },
+    // 教学模式分析
+    getTeachingModeData(_dataList, fileId) {
+      return new Promise(async (resolve) => {
+        let _continuousTime = 0;
+        let _totalTime = 0;
+        let _continuousRole = "老师";
+        let _teacherTime = 0;
+        _dataList.forEach((item, index) => {
+          if (index == 0) {
+            //第一个
+            _continuousRole = item.role;
+          } else if (_dataList.length - 1 == index) {
+            //最后一个
+            if (_continuousRole == item.role) {
+              //连续对话了
+              _continuousTime += this.convertToSeconds(_dataList[index - 1].time);
+              _continuousTime += this.convertToSeconds(item.time);
+            } else {
+              //没连续对话
+              if (index >= 2) {
+                if (_dataList[index - 2].role == _dataList[index - 1].role) {
+                  _continuousTime += this.convertToSeconds(
+                    _dataList[index - 1].time
+                  );
+                } else {
+                  _continuousRole = item.role;
+                }
+              } else {
+                _continuousRole = item.role;
+              }
+            }
+          } else {
+            if (_continuousRole == item.role) {
+              //连续对话了
+              _continuousTime += this.convertToSeconds(_dataList[index - 1].time);
+            } else {
+              //没连续对话
+              if (index >= 2) {
+                if (_dataList[index - 2].role == _dataList[index - 1].role) {
+                  _continuousTime += this.convertToSeconds(
+                    _dataList[index - 1].time
+                  );
+                } else {
+                  _continuousRole = item.role;
+                }
+              } else {
+                _continuousRole = item.role;
+              }
+            }
+          }
+
+          if (item.role == "老师") {
+            _teacherTime += this.convertToSeconds(item.time);
+          }
+
+          _totalTime += this.convertToSeconds(item.time);
+        });
+
+        let _RT = (_teacherTime / _totalTime).toFixed(2);
+        let _CH = (_continuousTime / _totalTime).toFixed(2);
+
+        let _msg = `## 任务
+根据FIAS(弗兰德斯互动分析系统)理论,计算获得某一节课的RT和CH值。请你结合FIAS相关知识进行分析,使用3句完整的话对整个课堂进行分析,需注意包含这些内容:分析该课堂所属的教学模型,描述课堂的整体表现与特征,肯定老师做出的努力,以及给出相应的建议。
+## 你的知识
+根据RT和CH的值,教学模式通常被分为以下几种类型: 练习型:RT ≤ 0.3,表示学生行为占主导,教师行为较少。 讲授型:RT ≥ 0.7,表示教师行为占主导,学生参与较少。 对话型:CH ≥ 0.4,表示师生之间有较多的互动和转换。 混合型:0.3 < RT < 0.7,CH < 0.4,表示教学中既有教师讲授也有学生参与,但两者都不占绝对优势。
+## 数据
+RT:${_RT}
+CH:${_CH}
+`;
+        let message = await this.getAiContentMixin({ _msg: _msg, fileId: fileId })
+
+        if (message.data == 1) {
+          return resolve({ RT: _RT, CH: _CH, message: "" })
+        } else {
+          return resolve({ RT: _RT, CH: _CH, message: message.data })
+        }
+      })
+    },
+    //光谱图
+    getSpectrogram(_dataList, fileId, content, assistant) {
+      return new Promise(async (resolve) => {
+        try {
+          this.getContentTableMixin(content).then(async res => {
+            if (res.length <= 0) {
+              resolve({ data: 1, err: "无表格数据" })
+            }
+            let _tableData = res;
+            let _delIndex = _tableData.findIndex(i => i.includes("时间点"))
+            _tableData = _tableData.slice(_delIndex + 1)
+            let _result = [];
+            let identity = "老师"; //0:老师 1:学生
+            let startTime = "";
+            let endTime = "";
+            let sumTime = 0;
+            let upTime = '00:00:00';
+
+            _dataList.forEach((item, index) => {
+              if (index == 0) {
+                //第一个
+                identity = item.role;
+                startTime = item.startTime;
+                endTime = item.endTime;
+                sumTime = (this.convertToSeconds(item.endTime) - this.convertToSeconds(upTime));
+                upTime = item.endTime
+                // console.log(item.endTime,item.startTime,(this.convertToSeconds(item.endTime) - this.convertToSeconds(item.startTime)))
+                return;
+              }
+              if (item.role == identity) {
+                //没更换角色
+                sumTime += (this.convertToSeconds(item.endTime) - this.convertToSeconds(upTime));
+                endTime = item.endTime;
+                upTime = item.endTime
+                // console.log(item.endTime,item.startTime,(this.convertToSeconds(item.endTime) - this.convertToSeconds(item.startTime)))
+              } else {
+                //更换角色了
+                _result.push({
+                  startTime: startTime,
+                  endTime: endTime,
+                  identity: identity,
+                  sumTime: sumTime
+                });
+                identity = item.role;
+                startTime = item.startTime;
+                endTime = item.endTime;
+                sumTime = (this.convertToSeconds(item.endTime) - this.convertToSeconds(upTime));
+                upTime = item.endTime
+                // console.log(item.endTime,item.startTime,(this.convertToSeconds(item.endTime) - this.convertToSeconds(item.startTime)))
+              }
+              if (index == _dataList.length - 1) {
+                // console.log("👉???",this.convertToSeconds(item.endTime))
+              }
+            });
+
+            let breakpoint = [];
+
+            breakpoint = _tableData.map(i => this.convertToSeconds(i[0]))
+
+            _result = _result.filter(
+              i =>
+                i.identity == "老师" ||
+                i.identity == "学生"
+            );
+            // let
+            let _data = {
+              data: [],
+              breakpoint: []
+            };
+
+            _data.data = _result.map(i => ({ role: i.identity, type: i.identity == "老师" ? 0 : 1, value: i.sumTime }));
+            _data.breakpoint = breakpoint;
+
+            let _msg = assistant.tips;
+
+            let message = await this.getAiContentMixin({ _msg: _msg, fileId: fileId })
+
+            if (message.data == 1) {
+              return resolve({ eCharts: _data, message: "" })
+            } else {
+              return resolve({ eCharts: _data, message: message.data })
+            }
+            // spectrogramData  _data
+
+
+          });
+        } catch (e) {
+          return resolve({ data: 1, err: e })
+        }
+      })
+
+    },
+    getAiContentMixin(obj) {
+      return new Promise((resolve) => {
+        let { _msg, fileId } = obj
+        let parm = {
+          id: "f8e1ebb2-2e0d-11ef-8bf4-12e77c4cb76b",
+          message: _msg,
+          session_name: uuidv4(),
+          userId: this.userId,
+          file_ids: fileId ? [fileId] : [],
+          model: "gpt-4o-2024-11-20",
+          sound_url: "",
+          temperature: 0.2,
+          top_p: 1,
+          max_completion_tokens: 4096,
+          stream: false,
+          uid: uuidv4()
+        };
+
+        this.ajax
+          .post("https://appapi.cocorobo.cn/api/agentchats/ai_agent_chat", parm)
+          .then(res => {
+            let _data = res.data;
+            resolve({ data: _data.message })
+          })
+          .catch(err => {
+            resolve({ data: 1, err: err })
+          });
+      })
+    },
+    convertToSeconds(time) {
+      let parts = time.split(":");
+      let seconds = +parts[0] * 3600 + +parts[1] * 60 + +parts[2];
+      return seconds;
+    },
+    //创建课堂
+    createClassMixin(data) {
+      return new Promise((resolve) => {
+        let _analysisList = data.analysisList;
+        let createJson = _analysisList.map(i => {
+          return {
+            jsonData: i.jsonData,
+            type: i.Type,
+            index: i.tIndex
+          }
+        })
+        createJson = createJson.filter(i => !i.isOtherData && converter(i.jsonData.name) != converter("词频词汇分析"));
+        let params = {
+          tid: uuidv4(),
+          userid: this.userId,
+          template: createJson
+        }
+        this.ajax
+          .post(
+            "https://gpt4.cocorobo.cn/insert_classroom_observation_template",
+            params
+          )
+          .then(res => {
+            let _data = res.data.FunctionResponse;
+            if (converter(_data.message) == converter("创建成功")) {
+              this.ajax
+                .post("https://gpt4.cocorobo.cn/insert_classroom_observation", {
+                  tid: params.tid,
+                  type: 10,
+                  index: 0,
+                  json_data: JSON.stringify({ file_ids: data.file_ids }),
+                  userid: this.userId
+                })
+                .then(res2 => {
+                  let _data2 = res2.data.FunctionResponse;
+                  if (converter(_data2.message) == converter("创建成功")) {
+                    let newOption = { id: uuidv4(), label: data.baseMessage.courseName, value: params.tid }
+                    let params2 = {
+                      tid: params.tid,
+                      type: 0,
+                    }
+                    this.ajax
+                      .post(
+                        "https://gpt4.cocorobo.cn/get_classroom_observation_new",
+                        params2
+                      ).then(res3 => {
+                        let _data = res3.data.FunctionResponse.result.length
+                          ? JSON.parse(res3.data.FunctionResponse.result)
+                          : [];
+
+                        //替换基础信息
+                        let _bmData = _data.find(i => i.tIndex == 0);
+                        let _imageList = _data.find(i => i.tIndex == 1);
+                        _imageList.jsonData = data.baseMessage.imageList
+
+                        if (_bmData) {
+                          _bmData.jsonData = data.baseMessage;
+                          delete _bmData.jsonData.imageList;
+                          if (data.tagList) {
+                            _bmData.jsonData.dialogTagList = data.tagList;
+                          } else {
+                            _bmData.jsonData.dialogTagList = [
+                              { value: 0, name: "通用课堂分析", loading: false },
+                              { value: 1, name: "学科课堂分析", loading: false },
+                              { value: 2, name: "扩展分析", loading: false }
+                            ]
+                          }
+                        }
+
+                        let arr = [{ id: _bmData.id, jsonData: JSON.stringify(_bmData.jsonData) }, { id: _imageList.id, jsonData: JSON.stringify(_imageList.jsonData) }]
+                        let promises = [];
+                        arr.forEach(i => {
+                          promises.push(new Promise((resolve) => {
+                            this.ajax
+                              .post("https://gpt4.cocorobo.cn/update_classroom_observation", {
+                                id: i.id,
+                                json_data: i.jsonData
+                              })
+                              .then(res => {
+                                resolve();
+                              })
+                              .catch(e => {
+                                console.log("保存失败", e);
+                                resolve()
+                              });
+                          }))
+                        })
+                        Promise.all(promises).then(res=>{
+                          resolve({ data: newOption,tid:params.tid })
+                        })
+
+                        // promises.push(new Promise((resolve)=>{
+                        //    this.ajax
+                        //   .post("https://gpt4.cocorobo.cn/update_classroom_observation", {
+                        //     id: _bmData.id,
+                        //     json_data: JSON.stringify(_bmData.jsonData)
+                        //   })
+                        //   .then(res => {
+                        //     resolve({ data: newOption,tid:params.tid })
+                        //   })
+                        //   .catch(e => {
+                        //     console.log("保存失败", e);
+                        //     resolve({ data: newOption,tid:params.tid })
+                        //   });
+                        // }))
+
+
+                        // Promise.all(()=>{
+
+                        // },)
+                        // promises.push(new Promise((resolve)=>{
+
+                        // }))
+
+
+                        // 保存修改信息
+                        // this.ajax
+                        //   .post("https://gpt4.cocorobo.cn/update_classroom_observation", {
+                        //     id: _bmData.id,
+                        //     json_data: JSON.stringify(_bmData.jsonData)
+                        //   })
+                        //   .then(res => {
+                        //     resolve({ data: newOption,tid:params.tid })
+                        //   })
+                        //   .catch(e => {
+                        //     console.log("保存失败", e);
+                        //     resolve({ data: newOption,tid:params.tid })
+                        //   });
+                      }).catch(err => {
+                        console.log("修改基础信息失败", err)
+                        resolve({ data: 1, err: err })
+                      })
+                  }
+                }).catch(err => {
+                  resolve({ data: 1, err: err })
+                  console.log("存储fileId失败")
+                  console.log(err)
+                })
+            }
+          }).catch(err => {
+            resolve({ data: 1, err: err })
+            console.log("创建课堂失败")
+            console.log(err)
+          })
+      })
+    },
+  }
+};

+ 27 - 6
src/components/pages/sassPlatform/index.vue

@@ -47,6 +47,7 @@ export default {
       oid: this.$route.query.oid,
       org: this.$route.query.org,
       role:this.$route.query.role,
+      userData:null
     }
   },
   computed:{
@@ -85,11 +86,12 @@ export default {
             i.open = false;
 
             if(i.id=='e18d88b3-e828-11ef-b508-005056924926'){
-              _children.push(...[
-                {name:"年度考核",type:"annualAssessment",navIndex:`${index}-1`},
-                {name:"考核数据可视化",type:"evaluationDataVisualization",navIndex:`${index}-2`},
-                ]
-              )
+
+
+              if(this.userData && this.userData.type === 1 && this.userData.role == 1){
+                _children.push({name:"年度考核",type:"annualAssessment",navIndex:`${index}-1`})
+              }
+              _children.push({name:"考核数据可视化",type:"evaluationDataVisualization",navIndex:`${index}-2`})
               i.open = true;
             }
             i.children = _children;
@@ -123,14 +125,33 @@ export default {
           "&back=sass"
       );
     },
+    getUser(uid) {
+      return new Promise(resolve => {
+        let params = { uid: uid };
+        this.ajax
+          .get(this.$store.state.api + "getUser", params)
+          .then(res => {
+            let data = res.data[0][0];
+            this.userData = data;
+            resolve()
+          })
+          .catch(err => {
+            console.error(err);
+            resolve()
+          });
+      });
+    },
   },
   mounted(){
-    this.getNavType().then(_=>{
+    this.getUser(this.userId).then(()=>{
+      this.getNavType().then(_=>{
       if(this.navList.length>0){
         let _data = this.navList[0].children[0];
         this.changeNavIndex(_data.navIndex,_data)
       }
     });
+    })
+
   }
 }
 </script>

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott