SanHQin 11 months ago
parent
commit
cd08d037d4

+ 1 - 0
package.json

@@ -28,6 +28,7 @@
     "lodash": "^4.17.15",
     "nprogress": "^0.2.0",
     "opencc-js": "^1.0.5",
+    "papaparse": "^5.4.1",
     "regenerator-runtime": "^0.13.5",
     "vant": "^2.12.7",
     "vconsole": "^3.3.4",

+ 18 - 0
src/api/classObserve.js

@@ -139,3 +139,21 @@ export function updateClassroomDefaultRequest(data){//修改模板数据
     hideloading: true
 	})
 }
+
+export function insertClassroomTemplateRequest(data){//修改模板数据
+	return request({
+		url: '/insertClassroomTemplate',
+    method: 'post',
+    data,
+    hideloading: true
+	})
+}
+
+export function upload_file_knowledgeRequest(data){//删除模板数据
+  return request2({
+		url: 'https://gpt4.cocorobo.cn/upload_file_knowledge',
+    method: 'put',
+    data,
+    hideloading: true
+	})
+}

+ 1 - 0
src/assets/images/classObserve/start.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1723615529272" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7322" width="200" height="200" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M512 32a480 480 0 1 1 0 960 480 480 0 0 1 0-960zM512 128a384 384 0 1 0 0 768A384 384 0 0 0 512 128zM428.16 320.704a32 32 0 0 1 18.048 5.504l234.368 159.36a32 32 0 0 1 0 52.928l-234.368 159.296a32 32 0 0 1-49.984-26.496V352.704a32 32 0 0 1 32-32z" fill="#000000" p-id="7323"></path></svg>

+ 1 - 0
src/assets/images/classObserve/uploadFile.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1723614898525" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5420" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.1953125" height="200"><path d="M192.104577 1023.615791a192.104577 192.104577 0 0 1-192.104577-192.104577V447.878374a64.034859 64.034859 0 0 1 128.069718 0v384.017049a64.034859 64.034859 0 0 0 64.034859 64.034859h640.34859a64.034859 64.034859 0 0 0 64.034859-64.034859V448.262583a64.034859 64.034859 0 0 1 128.069718 0v383.63284a192.104577 192.104577 0 0 1-192.104577 192.104577z m256.139436-383.824945V218.569544L365.44694 301.302582a64.034859 64.034859 0 0 1-90.54529-90.417221l192.104577-192.104577a64.034859 64.034859 0 0 1 90.609325 0l177.184455 176.99235a64.034859 64.034859 0 1 1-90.545291 90.353186L576.313731 218.697614v421.093232a64.034859 64.034859 0 1 1-128.069718 0z" fill="black" p-id="5421"></path></svg>

+ 431 - 51
src/views/classObserve/homePage.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="observe">
+  <div class="observe" v-loading="loading">
     <div class="top">
       <div class="Title">
         <div>课堂观察</div>
@@ -45,28 +45,76 @@
       <div class="chat">
         <div class="chatTxt" v-text="bmData.jsonData ? bmData.jsonData.transcriptionData : ''"></div>
         <img src="../../assets/images/classObserve/waveanimation.png" alt="" />
-        <div class="time">00:00</div>
+        <div class="time">{{ recordedForm.time }}</div>
       </div>
-      <div class="controlArea">
-        <img @click="goChat" src="../../assets/images/classObserve/rootper.svg" alt="" />
-				<van-popover placement="top" v-model="changeLanguageShow" trigger="click">
-					<div class="languageList">
-						<div :class="[choiceLanguageIndex==item.index?'l_active':'']" v-for="(item,index) in languageList" :key="index" @click.stop="changeLanguageFn(item.index)">{{ item.label }}</div>
-					</div>
-					<template #reference>
-						<img src="../../assets/images/classObserve/langcut.svg" alt="" />
-					</template>
-				</van-popover>
-       
-        <img @click="ctrlRecord" v-if="isParse" src="../../assets/images/classObserve/endLang.svg" alt="" />
-        <img @click="ctrlRecord" v-else src="../../assets/images/classObserve/recording.svg" alt="" />
-        <img src="../../assets/images/classObserve/suspend.svg" alt="" />
-        <div @click="historyBtn" style="position: relative;">
-          <span
-            style="position: absolute;top: -5px;right: -9px;color: rgba(54, 129, 252, 1);width: 15px;font-size: 10px;"
-            >{{ classList.length }}</span
-          >
-          <img src="../../assets/images/classObserve/book.svg" alt="" />
+      <div class="controlArea" v-loading="recordedForm.loading">
+        <div class="ca_left">
+          <img
+            
+            @click="goChat"
+            src="../../assets/images/classObserve/rootper.svg"
+            alt=""
+          />
+          <van-popover placement="top" v-model="changeLanguageShow" trigger="click">
+            <div class="languageList">
+              <div
+                :class="[choiceLanguageIndex == item.index ? 'l_active' : '']"
+                v-for="(item, index) in languageList"
+                :key="index"
+                @click.stop="changeLanguageFn(item.index)"
+              >
+                {{ item.label }}
+              </div>
+            </div>
+            <template #reference>
+              <img  src="../../assets/images/classObserve/langcut.svg" alt="" />
+            </template>
+          </van-popover>
+        </div>
+
+        <div class="recordBtn">
+          <img
+            @click="endRecord"
+            v-if="[1, 2].includes(recordedForm.status)"
+            src="../../assets/images/classObserve/endLang.svg"
+            alt=""
+          />
+          <img
+            @click="startRecord"
+            v-if="[0, 3].includes(recordedForm.status)"
+            src="../../assets/images/classObserve/recording.svg"
+            alt=""
+          />
+        </div>
+        <div class="ca_right">
+          <img
+						style="transform: scale(1.1,1.1);"
+            src="../../assets/images/classObserve/suspend.svg"
+            alt=""
+            v-if="[1].includes(recordedForm.status)"
+            @click.stop="stopRecord"
+          />
+          <img
+						
+            src="../../assets/images/classObserve/start.svg"
+            alt=""
+            v-if="[2].includes(recordedForm.status)"
+            @click.stop="reStartRecord"
+          />
+          <img
+						style="transform: scale(.8,.8);"
+            src="../../assets/images/classObserve/uploadFile.svg"
+            alt=""
+            v-if="[0, 3].includes(recordedForm.status)"
+            @click.stop="uploadFileFn"
+          />
+          <div @click="historyBtn" style="position: relative;">
+            <span
+              style="position: absolute;top: -3px;right: -6px;color: rgba(54, 129, 252, 1);width: 15px;font-size: 10px;"
+              >{{ classList.length }}</span
+            >
+            <img style="transform: scale(.8,.8);" src="../../assets/images/classObserve/book.svg" alt="" />
+          </div>
         </div>
       </div>
       <div class="selectBtn">
@@ -133,12 +181,60 @@
         </div>
       </div>
     </van-action-sheet>
+
+		<!-- 录音转文字 -->
+    <iframe
+      allow="camera *; microphone *;display-capture;midi;encrypted-media;"
+      src="https://beta.cloud.cocorobo.cn/browser/public/index.html"
+      ref="iiframe"
+      v-show="false"
+    ></iframe>
   </div>
 </template>
 
 <script>
 import { Dialog } from 'vant'
 import { loginOut } from '@/api/user'
+import _ from "lodash";
+import Papa from "papaparse";
+import '../../utils/aws-sdk-2.235.1.min.js'
+import {upload_file_knowledgeRequest } from '@/api/classObserve.js'
+
+const getFile = (url) => {
+  return new Promise((resolve, reject) => {
+    var credentials = {
+      accessKeyId: "AKIATLPEDU37QV5CHLMH",
+      secretAccessKey: "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",
+    }; //秘钥形式的登录上传
+    window.AWS.config.update(credentials);
+    window.AWS.config.region = "cn-northwest-1"; //设置区域
+    let url2 = url;
+    let _url2 = "";
+    if (url2.indexOf("https://view.officeapps.live.com/op/view.aspx?src=") != -1) {
+      _url2 = url2.split("https://view.officeapps.live.com/op/view.aspx?src=")[1];
+    } else {
+      _url2 = url2;
+    }
+    var s3 = new window.AWS.S3({ params: { Bucket: "ccrb" } });
+    let name = decodeURIComponent(
+      _url2.split("https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/")[1]
+    );
+    var params = {
+      Bucket: "ccrb",
+      Key: name,
+    };
+    s3.getObject(params, function (err, data) {
+      if (err) {
+        console.log(err, err.stack);
+        resolve({ data: 1 });
+      } else {
+        const fileContent = data.Body.toString("utf-8");
+        resolve({ data: fileContent });
+      } // sxuccessful response
+    });
+    // axios({
+  });
+};
 export default {
   props: {
     page: {
@@ -161,21 +257,38 @@ export default {
   data() {
     return {
       isParse: false,
+			loading:false,
+      recordedForm: {
+        time: '00:00:00', //时间
+        status: 0, //0--未录音  1--正在录音  2--暂停  3--录音结束
+        timer: null,
+        timeDuration: 0,
+        audioBlob: [],
+        startTime: 0,
+        endTime: 0,
+        textList: [],
+        loading: false
+      },
       historyShow: false,
+			uploadFileLoading:false,
       abuShowId: '',
       historyListLoading: false,
       addNewCourseShow: false,
-			changeLanguageShow:false,
-			languageList:[{index:13,label:"英语"},{index:3,label:"粤语"},{index:2,label:"普通话"},],
-			choiceLanguageIndex:2,
+      changeLanguageShow: false,
+      languageList: [
+        { index: 13, label: '英语' },
+        { index: 3, label: '粤语' },
+        { index: 2, label: '普通话' }
+      ],
+      choiceLanguageIndex: 2
     }
   },
   methods: {
-		changeLanguageFn(newIndex){
-			if(this.isParse)return this.$toast("正在录音中...")
-			this.choiceLanguageIndex = newIndex;
-			this.changeLanguageShow = false;
-		},
+    changeLanguageFn(newIndex) {
+      if (this.isParse) return this.$toast('正在录音中...')
+      this.choiceLanguageIndex = newIndex
+      this.changeLanguageShow = false
+    },
     goChat() {
       this.$router.push({ path: '/aiChat', query: {} })
     },
@@ -210,7 +323,233 @@ export default {
     ctrlRecord() {
       this.isParse = !this.isParse
     },
+    endRecord() {
+			if(this.recordedForm.loading)return;
+      console.log('结束录音')
+      this.recordedForm.status = 3
+    },
+    startRecord() {
+			// if(this.recordedForm.loading)return;
+			// if(!this.tid){
+			// 	return this.$parent.addNewCourseByDefault().then(_=>{
+			// 		this.startRecord()
+			// 	})
+			// }
+			// this.$toast.success("已开始录音")
+      // console.log('开始录音')
+      this.recordedForm.status = 1
+    },
+    stopRecord() {
+			if(this.recordedForm.loading)return;
+      console.log('暂停录音')
+      this.recordedForm.status = 2
+    },
+    reStartRecord() {
+			if(this.recordedForm.loading)return;
+      console.log('继续录音')
+      this.recordedForm.status = 1
+    },
+    uploadFileFn() {
+			if(!this.tid){
+				return this.$toast("请先选择课堂或者创建课堂")
+				// return this.$parent.addNewCourseByDefault().then(_=>{
+				// 	this.uploadFileFn()
+				// })
+			}
+			if (this.uploadFileLoading) return this.$toast("请稍等...");
+      let input = document.createElement("input");
+      input.type = "file";
+      // input.accept = ".wav";
+      // input.accept = "audio/*, .txt, .pdf, .xlsx";
+      input.accept = ".wav,.txt,.pdf,.xlsx,.doc,.docx,.csv";
+      input.click();
+      input.onchange = () => {
+        this.uploadFileLoading = true;
+        let file = input.files[0];
+        if (!/\.(wav|txt|pdf|xlsx|doc|docx|csv)$/i.test(file.name)) {
+          this.uploadFileLoading = false;
+          return this.$toast.error(
+            "请上传.wav,.txt,.pdf,.xlsx,.doc,.docx,.csv格式的文件"
+          );
+        }else{
+					
+					this.uploadFile(file, { changeText: true, flag: true });
+				}
+			}
+    },
+		uploadFile(file, { changeText = true, flag = true }) {
+      var credentials = {
+        accessKeyId: "AKIATLPEDU37QV5CHLMH",
+        secretAccessKey: "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",
+      }; //秘钥形式的登录上传
+      window.AWS.config.update(credentials);
+      window.AWS.config.region = "cn-northwest-1"; //设置区域
+
+      var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } }); //选择桶
+      var _this = this;
+
+      if (file) {
+        this.loading = true;
+        // this.progressData.uploadLoading = true;
+        // this.progressData.value = 0;
+        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.$toast.fail("上传失败");
+              _this.uploadFileLoading = false;
+              _this.loading = false;
+              // _this.progressData.uploadLoading = false;
+            } else {
+              // 判断是不是音频文件
+              const audioRegex = /\.(mp3|wav|ogg|flac|m4a)$/i;
+              const txtRegex = /\.(txt|csv)$/i;
+              const otherRegex = /\.(pdf|xlsx|doc|docx)$/i;
+              // if (audioRegex.test(data.Location)) {
+              // 	// console.log(data);
+              // 	_this.uploadWavFileAndGetText(file)
+              // 	_this.$emit("changeAudioUrl", data);
+
+              // 	// console.log("修改音频文件");
+              // 	// console.log(data)
+              // 	_this.uploadFileLoading = false;
+              // }else if(txtRegex.test(data.Location)){
+              // 	console.log("这hi是一个txt文件")
+              // } else if(otherRegex.test(data.Location)){
+              //
+              if (audioRegex.test(data.Location)) {
+                if (changeText) _this.wavFileGetText(file);
+								_this.$parent.changeAudioUrl(data);
+                // _this.$emit("changeAudioUrl", data);
+                _this.loading = false;
+                _this.recordedForm.audioBlob = [];
+                _this.recordedForm.time = "00:00:00";
+                _this.recordedForm.timeDuration = 0;
+                // _this.progressData.uploadLoading = false;
+                _this.recordedForm.textList = [];
+                _this.$parent.saveEditorBar();
+                return;
+              }
+
+							upload_file_knowledgeRequest({
+                  url: data.Location,
+                })
+                .then((res) => {
+                  let _data = res.FunctionResponse;
+                  if (_data.result && _data.result.id) {
+										_this.$parent.changeFileId(_data.result.id)
+                    // _this.$emit("updateFileId", _data.result.id);
+                    // _this.$message.success("成功获取fileId");
+                    _this.uploadFileLoading = false;
+                    //处理文件
+                    if (txtRegex.test(data.Location)) {
+                      //txt
+                      getFile(data.Location).then((_res) => {
+                        _this.controlsStatus = 2;
+                        _this.showIndexPage = false;
+                        _this.pageStatus = 2;
+                        _this.$parent.bmData.jsonData.editorBarData.type = "0";
+                        // _this.transcriptionData.content = _res.data;
+                        if (flag) {
+                          const arr = Papa.parse(_res.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>`;
+                          _this.$parent.bmData.jsonData.editorBarData.content = _editorBarDataContent;
+                        } else {
+                          _this.$parent.bmData.jsonData.editorBarData.content = _res.data;
+                        }
+                        _this.$parent.bmData.jsonData.editorBarData.url = "";
+                        _this.$parent.saveEditorBar();
+                      });
+                    } else if (otherRegex.test(data.Location)) {
+                      //pdf、 docx、doc、xlxs
 
+                      _this.$parent.bmData.jsonData.editorBarData.type = "1";
+                      _this.$parent.bmData.jsonData.editorBarData.url = data.Location;
+                      _this.$parent.bmData.jsonData.editorBarData.content = "";
+                      _this.$parent.saveEditorBar();
+                      // console.log("pdf、xlsx、doc、docx文件处理");
+                    }
+                    _this.loading = false;
+                    // _this.progressData.uploadLoading = false;
+        
+                    
+                  } else {
+                    _this.$toast.fail("修改fileId失败");
+                  }
+
+                  // this.$emit("updateFileId", data.Location)
+                })
+                .catch((e) => {
+                  _this.uploadFileLoading = false;
+                  // _this.progressData.uploadLoading = false;
+                  console.log(e);
+                  _this.$toast.fail("获取fileId失败");
+                });
+              // }
+
+              // console.log(data.Location)
+            }
+          });
+      }
+    },
+		
     analysis() {
       this.$router.push({ path: '/outcome', query: {} })
     },
@@ -402,6 +741,7 @@ export default {
   }
   .time {
     color: rgba(54, 129, 252, 1);
+    width: 100%;
     font-size: 12px;
     display: flex;
     justify-content: center;
@@ -411,8 +751,48 @@ export default {
   display: flex;
   justify-content: space-between;
   align-items: center;
+  width: 100%;
+  height: 80px;
   img {
     object-fit: contain;
+  }
+	.ca_left{
+		box-sizing: border-box;
+		padding-right: 10px;
+		width: calc(50% - 30px);
+		height: 100%;
+		display: flex;
+		justify-content: space-around;
+		align-items: center;
+		img{
+			width: 28px;
+			height: 28px;
+		}
+	}
+	.ca_right{
+		box-sizing: border-box;
+		padding-left: 10px;
+		width: calc(50% - 30px);
+		height: 100%;
+		display: flex;
+		justify-content: space-around;
+		align-items: center;
+		img{
+			width: 28px;
+			height: 28px;
+		}
+	}
+  .recordBtn {
+    width: 60px;
+    height: 60px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    img {
+      width: 150%;
+      height: 150%;
+      object-fit: contain;
+    }
   }
 }
 .selectBtn {
@@ -553,26 +933,26 @@ export default {
   }
 }
 
-.languageList{
-	width: auto;
-	height: auto;
-	display: flex;
-	flex-direction: column;
-	justify-content: center;
-	align-items: center;
-	padding: 10px;
-	
-	div{
-		padding: 10px 20px;
-		display: flex;
-		justify-content: center;
-		align-items: center;
-		border-radius: 8px;
-		transition: .3s;
-	}
-	.l_active{
-		background-color: #d8d8d8a2;
-		color: rgba(54, 129, 252, 1);
-	}
+.languageList {
+  width: auto;
+  height: auto;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  padding: 10px;
+
+  div {
+    padding: 10px 20px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    border-radius: 8px;
+    transition: 0.3s;
+  }
+  .l_active {
+    background-color: #d8d8d8a2;
+    color: rgba(54, 129, 252, 1);
+  }
 }
 </style>

+ 190 - 8
src/views/classObserve/index.vue

@@ -4,7 +4,7 @@
       ref="homePageRef"
       @cutPage="cutPage"
       :page="page"
-      v-if="page == 1"
+      v-show="page == 1"
       :baseMessageLoading="baseMessageLoading"
       :classList="classList"
       :tid="tid"
@@ -28,7 +28,7 @@
       :imageList="imageList"
     ></classInfo>
     <stencilled ref="stencilledRef" @cutPage="cutPage" :page="page" v-if="page == 5 && userId"></stencilled>
-    <editTel ref="editTelRef" @cutPage="cutPage" :page="page" v-if="page == 6"></editTel>
+    <editTel ref="editTelRef" @cutPage="cutPage" :dataList="dataList" :page="page" v-if="page == 6"></editTel>
     <addTel ref="addTelRef" @cutPage="cutPage" :page="page" v-if="page == 7"></addTel>
     <outcome
       ref="outcomeRef"
@@ -50,6 +50,7 @@ import editTel from './editTel'
 import addTel from './addTel'
 import outcome from './outcome.vue'
 import { v4 as uuidv4 } from 'uuid'
+import _ from 'lodash'
 import {
   updateObsRequest,
   getCourseListRequest,
@@ -90,7 +91,15 @@ export default {
       },
       imageList: {},
       dataList: [],
-      tid: ''
+      tid: '',
+      editorBarData: {
+        type: '0', //0---文字   1-文件
+        content: '',
+        url: ''
+      },
+			fileId:"",
+			fileIdId:"",
+      actionTypesMap: {}
     }
   },
   methods: {
@@ -145,12 +154,23 @@ export default {
       })
     },
     // 切换课堂
-    changeTid(newTid) {
+    async changeTid(newTid) {
       if (this.tid == newTid) return
       let _flag = this.tid !== newTid
       this.tid = newTid
       if (_flag) {
         this.getData()
+      }
+			// 获取fileId
+			this.getFileIdId();
+      if (!this.tid) {
+        this.actionTypesMap = undefined
+        return
+      }
+      this.actionTypesMap = await this.loadActionTypesMap()
+      if (!this.actionTypesMap) {
+        await this.insertActionTypes()
+        this.actionTypesMap = await this.loadActionTypesMap()
       }
     },
     //编辑课堂名称
@@ -204,7 +224,9 @@ export default {
           //   this.changeTid(this.classList[0].value)
           // }
           this.tid = ''
-          this.dataList = ''
+					this.fileId = "";
+					this.fileIdId = "";
+          this.dataList = []
           this.bmData = {
             id: '',
             tId: '',
@@ -220,7 +242,7 @@ export default {
               textbook: ''
             }
           }
-					this.imageList = {};
+          this.imageList = {}
           this.$refs.homePageRef.historyListLoading = false
         })
       })
@@ -236,7 +258,9 @@ export default {
             resolve()
           })
           .catch(e => {
-            this.$message.error('保存失败')
+						console.log(e)
+						console.log("保存失败")
+            // this.$toast.fail('保存失败')
             resolve()
           })
       })
@@ -255,6 +279,7 @@ export default {
             // 基础信息
             _bmData.jsonData = JSON.parse(_bmData.jsonData)
             _bmData.jsonData.time ? '' : (_bmData.jsonData.time = '')
+						_bmData.jsonData.editorBarData ? '' :(_bmData.jsonData.editorBarData = { type: '0',content: '',url: ''})
             // 图片
             let _imageList = _data.find(i => i.tIndex == 1)
             _imageList.jsonData = JSON.parse(_imageList.jsonData)
@@ -473,11 +498,12 @@ export default {
                 this.$nextTick(() => {
                   this.getCourseList().then(_ => {})
                   // 	this.getCourseList().then((_) => {
-                  // 		this.getFileIdId();
+                  		this.getFileIdId();
                   // 		this.$refs.messageAreaRef.getData();
                   // 		this.$refs.chatAreaRef.getData();
                   // 		resolve();
                   // 	});
+                  resolve()
                 })
               } else {
                 this.$toast.fail('创建fileIds失败')
@@ -492,6 +518,162 @@ export default {
           }
         })
       })
+    },
+		// 获取修改fileId的ID
+		getFileIdId() {
+			if (!this.tid) return;
+			let pram = {
+				tid: this.tid,
+				type: "10",
+			};
+			this.fileIdId = "";
+			this.fileId = "";
+			getObsRequest(pram)
+				.then((res) => {
+					console.log(res);
+					let _data = res.FunctionResponse.result.length
+						? JSON.parse(res.FunctionResponse.result)
+						: [];
+					if (_data.length <= 0) return;
+					this.fileIdId = _data[0].id;
+					if (_data[0].jsonData != "") {
+						this.fileId = JSON.parse(_data[0].jsonData).file_ids;
+					} else {
+						this.fileId = "";
+					}
+				});
+		},
+		changeFileId(newFileId){
+			this.saveData({
+				id:this.fileIdId,
+				json_data: JSON.stringify({
+          file_ids: newFileId,
+        }),
+			}).then(res=>{
+				console.log("更改并保存fileID成功")
+				this.getFileIdId();
+			}).catch(e=>{
+				console.log("更改并保存fileID失败",e)
+			})
+		},
+    // 切换录音文件
+    changeAudioUrl(data) {
+      this.imageList.jsonData.fileList = []
+      let audio = {
+        name: data.key,
+        status: 'success',
+        uid: '1',
+        url: data.Location
+      }
+      this.imageList.jsonData.fileList.push(audio)
+      this.saveData(this.imageList).then(res => {
+        this.$toast.success('更换录音文件成功')
+      })
+    },
+    // 保存转录文稿和原文速览
+    saveEditorBar(flag = false) {
+      if (!this.tid) return this.$toast.fail('请选择课堂')
+      if (this.bmData.jsonData.editorBarData.type == '0' && flag && this.bmData.jsonData.editorBarData.content) {
+        // 如果是文本则转成txt并保存
+        let _result = JSON.parse(JSON.stringify(this.bmData.jsonData.editorBarData))
+        var text = _result.content
+
+        // 创建一个Blob实例
+        var blob = new Blob([text], { type: 'text/plain;charset=utf-8' })
+        blob.lastModifiedDate = new Date()
+        blob.name = `${this.tid}-classroomObservation.txt`
+        return this.$refs.homePageRef.uploadFile(blob, { changeText: false, flag: false })
+      } else {
+        // this.loading = true;
+        // let div = document.createElement("div");
+        // div.innerHTML = this.editorBarData.content;
+        // return this.loading = false;
+
+        let _sentence = 0
+        let _words = 0
+        let _editorBarDataContentRows = []
+        let _actionTypes = []
+
+        if (this.bmData.jsonData.editorBarData.type == 0) {
+          let _data = this.bmData.jsonData.editorBarData.content
+          let _div = document.createRange().createContextualFragment(_data)
+          let _tableRows = _div.querySelectorAll(`table tbody tr`)
+          _tableRows.forEach((i, index) => {
+            while (i.cells.length > 7) {
+              i.removeChild(i.lastElementChild)
+            }
+						console.log(i)
+            const actionTypeCell = i.cells[6] && i.removeChild(i.cells[6])
+            _editorBarDataContentRows.push(i.outerHTML)
+            if (index == 0) return
+            if (i.cells[3].textContent != '') {
+              _sentence += 1
+              _words += i.cells[3].textContent.length
+            }
+            _actionTypes.push(_.get(actionTypeCell, 'textContent', ''))
+          })
+        }
+        const _editorBarDataContent = `<table
+					border="0"
+					width="100%"
+					cellpadding="0"
+					cellspacing="0"
+					style="text-align: center"
+				>
+					<tbody>
+						${_editorBarDataContentRows.join('')}
+					</tbody>
+				</table>
+				`
+
+        this.bmData.jsonData.editorBarData.sentenceNum = _sentence
+        this.bmData.jsonData.editorBarData.wordsNum = _words
+        let _saveWordData = this.dataList.find(i => i.Type == 0 && i.tIndex == 2)
+        if (_saveWordData) {
+          _saveWordData.jsonData.wordCountNum = _sentence
+          _saveWordData.jsonData.wordNum = _words
+          this.saveData(_saveWordData).then(_ => {
+            console.log('词频词汇分析已保存')
+          })
+        }
+				console.log(this.bmData.jsonData)
+        this.saveData(this.bmData).then(_ => {
+					console.log("转录问稿已保存")
+          this.loading = false
+        })
+        // // TODO 不同板块用id做key
+        this.actionTypesMap.jsonData['default'] = _actionTypes
+        this.saveActionTypesMap()
+      }
+    },
+    async loadActionTypesMap() {
+      const res = await getObsRequest({ tid: this.tid, type: '11' })
+      const result = _.get(res, ['FunctionResponse', 'result'], '[]')
+      if (result instanceof Array) {
+        return undefined
+      }
+      const data = _.get(JSON.parse(result), 0)
+      return { ...data, jsonData: JSON.parse(data.jsonData) }
+    },
+    async insertActionTypes() {
+      return await insertNewObsRequest({
+        tid: this.tid,
+        type: '11',
+        json_data: JSON.stringify({ default: [] }),
+        index: 0,
+        userid: this.userId
+      })
+    },
+    async saveActionTypesMap() {
+      try {
+        return await updateObsRequest({
+          id: this.actionTypesMap.id,
+          json_data: JSON.stringify(this.actionTypesMap.jsonData)
+        })
+      } catch (e) {
+        console.error(e)
+        this.$toast(e)
+      }
     }
   },
   mounted() {

+ 189 - 6
src/views/classObserve/outcome.vue

@@ -1,6 +1,6 @@
 <template>
-  <div class="outcome">
-    <bar @cutPage="cutPage" :tit="'分析结果'" :backPage="0"></bar>
+  <div class="outcome" v-loading="saveLoading">
+    <bar @cutPage="cutPage(1)" :tit="'分析结果'" :backPage="0"></bar>
     <div class="sortList">
       <div :class="[showIndex==0?'sortActive':'']" @click.stop="changeShowIndex(0)">通用</div>
       <div :class="[showIndex==1?'sortActive':'']" @click.stop="changeShowIndex(1)">学科</div>
@@ -16,10 +16,43 @@
         <img src="../../assets/images/classObserve/share.png" alt=""/>
         <span>分享</span>
       </div>
+
+			<div class="bb_box">
+				<div class="btn" @click.stop="saveTemplate()">
+        保存模板
+      </div>
+			
+			<div class="btn" @click.stop="AllAnalysis()">
+        一键分析
+      </div>
+
       <div class="btn" @click.stop="viewTheReport()">
         查看报告
       </div>
+			</div>
     </div>
+		<van-popup v-model="showPopup">
+      <div class="popupCon">
+        <div class="tit">模板信息</div>
+        <div class="bri">请根据提示补充模版信息</div>
+        <div>
+          <el-input v-model="form.name" placeholder="模版名称"></el-input>
+          <el-input type="textarea" :rows="3" resize="none" v-model="form.brief" placeholder="模版简介"></el-input>
+          <el-select v-model="form.subject" placeholder="所属学科" style="z-index: 2026;">
+            <el-option v-for="item in subjectList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+          </el-select>
+        </div>
+
+        <div class="switch">
+          <span style="margin-right: 5px;">公开到社区</span
+          ><el-switch v-model="form.per" active-color="rgba(54, 129, 252, 1)"> </el-switch>
+        </div>
+      </div>
+      <div class="btnS">
+        <div @click="cancelSaveTemplate">取消</div>
+        <div style="color: rgba(54, 129, 252, 1);" @click="saveInfo">保存</div>
+      </div>
+    </van-popup>
   </div>
 </template>
 
@@ -27,6 +60,7 @@
 import bar from './components/bar.vue'
 import analysisItem from './components/analysisItem.vue'
 import { Dialog } from 'vant';
+import {insertClassroomTemplateRequest} from '@/api/classObserve'
 export default {
   components: {
     bar,
@@ -48,14 +82,36 @@ export default {
   },
   data() {
     return {
+			userId:this.$store.state.user.id,
       abuShow: false,
       cellShow: false,
+			showPopup:false,
 			showIndex:0,
+			saveLoading:false,
+			form:{
+				name:"",
+				brief:"",
+				subject:"",
+				pre:false,
+			},
+			subjectList:[
+				{value:'1',label:'语文'},
+				{value:'2',label:'数学'},
+				{value:'3',label:'英语'},
+				{value:'4',label:'科学'},
+				{value:'5',label:'物理'},
+				{value:'6',label:'化学'},
+				{value:'7',label:'生物'},
+				{value:'8',label:'历史'},
+				{value:'9',label:'地理'},
+				{value:'10',label:'政治'},
+				
+			],
     }
   },
   methods: {
-    cutPage() {
-      this.$emit('cutPage', 1)
+    cutPage(page) {
+      this.$emit('cutPage', page)
     },
     ctrlShow() {
       this.cellShow = !this.cellShow
@@ -82,6 +138,61 @@ export default {
 		},
 		viewTheReport(){
 			console.log("查看报告");
+		},
+		AllAnalysis(){
+			console.log("一键分析")
+		},
+		saveTemplate(){
+			this.showPopup = !this.showPopup;
+		},
+		cancelSaveTemplate(){
+			this.form = {
+				name:"",
+				brief:"",
+				subject:"",
+				per:false,
+			};
+			this.showPopup = false;
+		},
+		saveInfo(){
+
+			if(!this.form.name.trim())return this.$toast.fail("请填写模板名称");
+			if(!this.form.subject.trim())return this.$toast.fail("请选择科目");
+			// if(!this.form.brief.trim())return this.$toast.fail("请填写模板简介");
+
+			this.saveLoading = true;
+			let _data = JSON.parse(JSON.stringify(this.dataList));
+			let _result = [];
+			
+			_data.forEach(i=>{
+				if(i.Type==0 && i.tIndex==2 )return;
+				i.jsonData.content = "";
+				i.jsonData.dataFileList = [];
+				i.jsonData.fileList = [];
+				i.createtime = "";
+				i.id = "",
+				i.tId = "",
+				i.userid = "";
+				_result.push(i)
+			})
+
+			let params = [{
+				title:this.form.name,
+				subject:this.form.subject,
+				uid:this.userId,
+				brief:this.form.brief,
+				per:this.form.per?1:0,
+				jsonData:JSON.stringify(_result),
+			}]
+
+			insertClassroomTemplateRequest(params).then(res=>{
+				this.$toast.success("保存为模板成功");
+				this.cancelSaveTemplate();
+				this.saveLoading = false;
+			}).catch(e=>{
+				this.$toast.fail("另存为模板失败")
+				console.log(e)
+			})
 		}
   }
 }
@@ -147,7 +258,8 @@ export default {
 .botBtn {
   background-color: #fff;
   width: 100%;
-  padding: 10px 25px;
+  padding: 10px 10px;
+	padding-left: 15px;
   box-sizing: border-box;
   display: flex;
   align-items: center;
@@ -161,7 +273,14 @@ export default {
     font-size: 400;
     color: rgba(4, 0, 0, 1);
   }
-  .btn {
+	.bb_box{
+		flex: 1;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		justify-content: space-around;
+		padding: 0;
+		.btn {
     flex: 1;
     background-color: rgba(54, 129, 252, 1);
     color: #fff;
@@ -169,9 +288,12 @@ export default {
     border-radius: 10px;
     display: flex;
     font-size: 16px;
+		margin: 0 5px;
     justify-content: center;
     align-items: center;
   }
+	}
+  
 }
 .abu {
   background-color: #fff;
@@ -204,4 +326,65 @@ export default {
     }
   }
 }
+
+/deep/ .van-popup--center {
+  border-radius: 10px;
+  width: 280px;
+}
+/deep/.el-input__inner {
+  border: 0;
+  background-color: rgba(243, 243, 243, 1);
+}
+/deep/.el-select {
+  width: 100%;
+}
+/deep/.el-textarea__inner {
+  border: 0;
+  background-color: rgba(243, 243, 243, 1);
+  margin: 10px 0;
+}
+
+/deep/.van-overlay{
+	z-index: 1999 !important;
+}
+
+/deep/.van-popup{
+	z-index: 2000 !important;
+}
+
+.popupCon {
+  padding: 10px 15px;
+  .tit {
+    width: 100%;
+    text-align: center;
+    font-size: 18px;
+    font-weight: 600;
+    padding: 10px 0;
+  }
+  .bri {
+    font-size: 16px;
+    font-weight: 400;
+    text-align: center;
+    color: rgba(0, 0, 0, 0.6);
+    padding-bottom: 10px;
+  }
+  .switch {
+    margin: 10px 0;
+    font-size: 14px;
+    // font-weight: 600;
+    color: rgba(0, 0, 0, 0.9);
+  }
+}
+.btnS {
+  display: flex;
+  border-top: 0.5px solid rgba(231, 231, 231, 1);
+  justify-content: space-between;
+  div {
+    flex: 1;
+    text-align: center;
+    padding: 17px 0;
+    font-size: 14px;
+    font-weight: 600;
+  }
+}
 </style>