SanHQin преди 7 месеца
родител
ревизия
881f939adb

+ 1 - 1
build/webpack.dev.conf.js

@@ -44,7 +44,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
     watchOptions: {
       poll: config.dev.poll,
     },
-    https: true // Enable HTTPS
+    // https: true // Enable HTTPS
   },
   plugins: [
     new webpack.DefinePlugin({

BIN
src/assets/icon/classroomObservation/rt-ch_echarts.png


+ 8 - 4
src/components/pages/classroomObservation/components/analysisSpecialItem.vue

@@ -178,7 +178,7 @@
 
       <!-- 光谱图 -->
       <echartsSpectrogram
-        style="max-height: 150px;max-width: 90%;width: 90%;height: 150px;margin: auto;margin-bottom: 50px;"
+        style="max-height: 200px;max-width: 90%;width: 90%;height: 200px;margin: auto;margin-bottom: 50px;"
         v-if="data.jsonData.spectrogramData && data.jsonData.mId == 'bfe844b1-7a45-11ef-9b30-005056b86db5'"
         :data="data.jsonData.spectrogramData"
       />
@@ -191,7 +191,9 @@
             converter(data.jsonData.name) != converter('S-T分析:师生互动分析')
         "
       />
-      <div class="rtCh" v-if="data.jsonData.RT && data.jsonData.CH">
+
+			<echartsRTCH v-if="data.jsonData.RT && data.jsonData.CH" :data="{RT:data.jsonData.RT,CH:data.jsonData.CH}" style="width: 100%;height: 350px;display: flex;justify-content: center;margin-bottom: 20px;"/>
+      <!-- <div class="rtCh" v-if="data.jsonData.RT && data.jsonData.CH">
         <img
           :src="
             require('../../../../assets/icon/classroomObservation/rt-ch.png')
@@ -201,7 +203,7 @@
           <span>RT={{ data.jsonData.RT }}</span>
           <span>CH={{ data.jsonData.CH }}</span>
         </div>
-      </div>
+      </div> -->
       <mdView :text="data.jsonData.content" />
     </div>
     <!-- <editNameDialog ref="editNameDialogRef" @success="changeNameSuccess"/> -->
@@ -220,12 +222,14 @@ import { v4 as uuidv4 } from "uuid";
 import echartsSpectrogram from "./echartsSpectrogram";
 // import editNameDialog from './editNameDialog.vue'
 import markdownIt from "markdown-it";
+import echartsRTCH from './echartsRTCH'
 export default {
   emits: ["delItem", "editItem", "saveItem"],
   components: {
     mdView,
     eChartTemplate,
-    echartsSpectrogram
+    echartsSpectrogram,
+		echartsRTCH
     // editNameDialog
   },
   props: {

+ 6 - 1
src/components/pages/classroomObservation/components/chatArea.vue

@@ -1987,7 +1987,8 @@ ${JSON.stringify(_list)}
     getChatList() {
       return new Promise((resolve, reject) => {
         if (!this.tid) return;
-        if (this.chatLoading) return this.$message.info("请稍等...");
+				let _copyTid = this.tid;
+        // if (this.chatLoading) return;
         this.chatList = [];
         this.chatLoading = true;
         let params = {
@@ -1999,6 +2000,10 @@ ${JSON.stringify(_list)}
         this.ajax
           .post("https://gpt4.cocorobo.cn/get_agent_park_chat", params)
           .then(res => {
+						if(_copyTid!=this.tid)return;
+						// 	this.chatLoading = false;
+						// 	return this.getChatList()
+						// };
             let _data = JSON.parse(res.data.FunctionResponse);
             if (_data.length > 0) {
               let _chatList = [];

+ 98 - 0
src/components/pages/classroomObservation/components/echartsRTCH.vue

@@ -0,0 +1,98 @@
+<template>
+  <div>
+    <canvas class="canvas" ref="canvasRef"></canvas>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    data: {
+      type: Object,
+      default: () => {
+        return { RT: 0, CH: 0 };
+      }
+    }
+  },
+  data() {
+    return {
+      canvas: null
+    };
+  },
+  methods: {
+    init() {
+      this.canvas = this.$refs.canvasRef;
+      if (!this.canvas) return;
+      let ctx = this.canvas.getContext("2d");
+      this.canvas.width = this.canvas.clientWidth * window.devicePixelRatio;
+      this.canvas.height = this.canvas.clientHeight * window.devicePixelRatio;
+      // 缩放绘图上下文
+      ctx.scale(1, 1);
+
+      let canvasWidth = this.canvas.width;
+      let canvasHeight = this.canvas.height;
+      let fontColor = "#1a7ad3";
+      ctx.imageSmoothingEnabled = false;
+      ctx.lineWidth = 1;
+      console.log(canvasWidth);
+      const img = new Image();
+      img.src = require("../../../../assets/icon/classroomObservation/rt-ch_echarts.png");
+      img.onload = () => {
+        ctx.drawImage(img, 25, 25, 250, 250);
+        ctx.beginPath();
+        ctx.arc((250*parseFloat(this.data.RT))+25,(250-(250*parseFloat(this.data.CH))+25), 4, 0, 2 * Math.PI);
+        ctx.fill();
+        ctx.stroke();
+      };
+
+      ctx.fillStyle = "black";
+      ctx.font = `20px serif`;
+      ctx.fillText("1", 10, 40);
+      ctx.fillText("Ch", 0, 150);
+      ctx.fillText("0", 10, 290);
+      ctx.fillText("Rt", 140, 295);
+      ctx.fillText("1", 280, 275);
+
+      ctx.fillStyle = fontColor;
+      ctx.font = "italic bold 24px Arial";
+      ctx.fillText(`RT=${this.data.RT}    CH=${this.data.CH}`, 40, 330);
+    },
+    drawRoundedRect(ctx, x, y, width, height, radius) {
+      // 限制 radius 的最大值,防止它超过矩形的宽度或高度的一半
+      const actualRadius = Math.min(radius, width / 2, height / 2);
+
+      ctx.beginPath();
+      ctx.moveTo(x + actualRadius, y); // 起点,矩形顶部的左侧
+
+      // 右上角的弧线
+      ctx.arcTo(x + width, y, x + width, y + height, actualRadius);
+
+      // 右下角的弧线
+      ctx.arcTo(x + width, y + height, x, y + height, actualRadius);
+
+      // 左下角的弧线
+      ctx.arcTo(x, y + height, x, y, actualRadius);
+
+      // 左上角的弧线
+      ctx.arcTo(x, y, x + width, y, actualRadius);
+
+      ctx.closePath();
+      ctx.fill(); // 填充颜色
+    }
+  },
+  mounted() {
+    this.init();
+    window.addEventListener("resize", () => {
+      if (!this.$refs.canvasRef) return;
+      this.init();
+    });
+  }
+};
+</script>
+
+<style scoped>
+.canvas {
+  width: 300px;
+  height: 350px;
+}
+</style>

+ 55 - 11
src/components/pages/classroomObservation/components/echartsSpectrogram.vue

@@ -16,7 +16,8 @@ export default {
   },
   data() {
     return {
-      canvas: null
+      canvas: null,
+      step: 300
     };
   },
   methods: {
@@ -30,6 +31,7 @@ export default {
       ctx.scale(1, 1);
 
       let canvasWidth = this.canvas.width;
+			let canvasWidth2 = canvasWidth - 20
       let canvasHeight = this.canvas.height;
       ctx.imageSmoothingEnabled = false;
       ctx.lineWidth = 1;
@@ -40,7 +42,7 @@ export default {
       const fontSize = 14; //字体大小
 
       ctx.fillStyle = teacherColor;
-      this.drawRoundedRect(ctx, 0, canvasHeight - 20, 20, 15, 5);
+      this.drawRoundedRect(ctx, 0, canvasHeight - 20, 20, 15, 4);
       // ctx.fillRect(0, canvasHeight - 20, 25, 20);
       ctx.fillStyle = "black";
       ctx.font = `${fontSize}px serif`;
@@ -48,21 +50,21 @@ export default {
 
       ctx.fillStyle = studentColor;
       // ctx.fillRect(100, canvasHeight - 20, 25, 20);
-      this.drawRoundedRect(ctx, 100, canvasHeight - 20, 20, 15, 5);
+      this.drawRoundedRect(ctx, 100, canvasHeight - 20, 20, 15, 4);
       ctx.fillStyle = "black";
       ctx.font = `${fontSize}px serif`;
       ctx.fillText("学生", 128, canvasHeight - 7);
       let sum = this.data.data.reduce((pre, cur) => (pre += cur.value), 0);
-
+			console.log(sum)
       // 当前x位置的起始点
-      let currentX = 0;
+      let currentX = 10;
       // 计算并绘制每个区域
       this.data.data.forEach(i => {
         const segmentWidth = parseFloat(
-          (i.value / (sum / canvasWidth)).toFixed(2)
+          (i.value / (sum / canvasWidth2)).toFixed(2)
         );
         ctx.fillStyle = i.type == 0 ? teacherColor : studentColor;
-        ctx.fillRect(currentX, 20, segmentWidth, canvasHeight - 60);
+        ctx.fillRect(currentX, 20, segmentWidth, canvasHeight - 100);
 
         // 更新x位置
         currentX += segmentWidth;
@@ -73,12 +75,38 @@ export default {
       ctx.lineWidth = 2;
 
       this.data.breakpoint.forEach(i => {
-        const breakpointPo = parseFloat((i / (sum / canvasWidth)).toFixed(2));
+        const breakpointPo = parseFloat((i / (sum / canvasWidth2)).toFixed(2));
         ctx.beginPath();
-        ctx.moveTo(breakpointPo, 0);
-        ctx.lineTo(breakpointPo, canvasHeight - 20);
+        ctx.moveTo(breakpointPo, 10);
+        ctx.lineTo(breakpointPo, canvasHeight - 70);
         ctx.stroke();
       });
+
+      let interval = parseFloat((this.step / (sum / canvasWidth2)).toFixed(2));
+      //绘制竖线
+      for (let i = 0; i < canvasWidth2; i += interval) {
+        ctx.beginPath();
+				ctx.strokeStyle = '#BFBFBF'
+        ctx.moveTo(i==0?10:i, canvasHeight - 70);
+        ctx.lineTo(i==0?10:i, canvasHeight - 55);
+        ctx.stroke();
+				ctx.fillStyle = "#868686";
+        let timeLabel = (((i / canvasWidth2) * sum)/60).toFixed(0); // 时间标识计算
+				ctx.font = `${fontSize}px serif`;
+				if(i==0){
+					ctx.fillText(`${timeLabel}min`, i+10, canvasHeight - 40);
+				}else if((i+interval)> canvasWidth2){
+					ctx.fillText(`${timeLabel}min`, i - 20, canvasHeight - 40);
+				}else{
+					ctx.fillText(`${timeLabel}min`, i-15, canvasHeight - 40);
+				}
+      }
+
+			ctx.beginPath();
+			ctx.strokeStyle = '#BFBFBF'
+			ctx.moveTo(10, canvasHeight - 55);
+			ctx.lineTo(canvasWidth2+10, canvasHeight - 55);
+			ctx.stroke();
     },
     drawRoundedRect(ctx, x, y, width, height, radius) {
       // 限制 radius 的最大值,防止它超过矩形的宽度或高度的一半
@@ -101,7 +129,23 @@ export default {
 
       ctx.closePath();
       ctx.fill(); // 填充颜色
-    }
+    },
+		formatTime(seconds) {
+  let h = Math.floor(seconds / 3600); // 小时
+  let m = Math.floor((seconds % 3600) / 60); // 分钟
+  let s = Math.floor(seconds % 60); // 秒数
+  
+  // 格式化为两位数
+  let formattedTime;
+  if (h > 0) {
+    // 如果有小时部分,格式化为 hh:mm:ss
+    formattedTime = `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
+  } else {
+    // 否则,格式化为 mm:ss
+    formattedTime = `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
+  }
+  return formattedTime;
+}
   },
   mounted() {
     this.init();

+ 29 - 20
src/components/pages/classroomObservation/components/messageArea.vue

@@ -50,7 +50,7 @@
         @changeAnalysisName="changeAnalysisName"
         @addNewAnalysisGroup="addNewAnalysisGroup"
         @delAnalysisGroup="delAnalysisGroup"
-				:dataList="dataList.filter(i => !(item.value == 0 && i.tIndex == 2))"
+        :dataList="dataList.filter(i => !(item.value == 0 && i.tIndex == 2))"
         :bmData="bmData.jsonData"
         :title="item.name"
         :dialogTagDataList="dialogTagDataList"
@@ -748,6 +748,7 @@ export default {
     // },
     getAnalysisData(type) {
       if (!this.tid) return;
+      let _copyTid = this.tid;
       return new Promise(resolve => {
         let params = {
           tid: this.tid,
@@ -789,6 +790,7 @@ export default {
             params
           )
           .then(res => {
+            if (_copyTid != this.tid) return;
             let _data = res.data.FunctionResponse.result.length
               ? JSON.parse(res.data.FunctionResponse.result)
               : [];
@@ -918,19 +920,24 @@ export default {
         });
       }
     },
-    getData() {
+    getData(arr = []) {
       return new Promise(resolve => {
         this.dataList = [];
+        this.$forceUpdate();
         if (this.tid) {
-          this.getAnalysisData(0).then(res => {
+          return this.getAnalysisData(0).then(res => {
             this.$nextTick(() => {
               let promises = [];
-              this.dialogTagList.forEach(i => {
-                if (i.value === 0) return;
-                promises.push(this.getAnalysisData(i.value));
-              });
-              Promise.all(promises).then(res => {
-                resolve();
+              this.$nextTick(() => {
+								let forData = arr.length?arr:this.dialogTagList;
+								this.dialogTagList = forData;
+                forData.forEach(i => {
+                  if (i.value === 0) return;
+                  promises.push(this.getAnalysisData(i.value));
+                });
+                Promise.all(promises).then(res => {
+                  resolve();
+                });
               });
             });
           });
@@ -1152,9 +1159,12 @@ export default {
           type: "warning"
         })
           .then(() => {
-            this.$refs["analysis0"][0].getReport();
-            this.$refs["analysis1"][0].getReport();
-            this.$refs["analysis2"][0].getReport();
+            this.dialogTagList.forEach(i => {
+              this.$refs[`analysis${i.value}`][0].getReport();
+            });
+            // this.$refs["analysis0"][0].getReport();
+            // this.$refs["analysis1"][0].getReport();
+            // this.$refs["analysis2"][0].getReport();
             this.$message.success("一键分析成功");
             // this.$refs.analysis3.getReport();
           })
@@ -1296,7 +1306,7 @@ export default {
     },
     delAnalysisGroup(data) {
       let _index = this.dialogTagList.findIndex(i => i.value === data.type);
-			this.dialogTagList[_index].loading = true
+      this.dialogTagList[_index].loading = true;
       let promises = [];
       data.groupId.forEach(i => {
         promises.push(this.delAnalysisItem2(i));
@@ -1304,14 +1314,14 @@ export default {
 
       if (promises.length > 0) {
         return Promise.all(promises).then(res => {
-					this.dialogTagList.splice(_index,1);
-					this.$message.success("删除分析分组成功");
-          this.saveData(this.bmData)
+          this.dialogTagList.splice(_index, 1);
+          this.$message.success("删除分析分组成功");
+          this.saveData(this.bmData);
         });
       } else {
-				this.dialogTagList.splice(_index,1);
-				this.$message.success("删除分析分组成功");
-        return this.saveData(this.bmData)
+        this.dialogTagList.splice(_index, 1);
+        this.$message.success("删除分析分组成功");
+        return this.saveData(this.bmData);
       }
     },
     delAnalysisItem2(id) {
@@ -1343,7 +1353,6 @@ export default {
       });
     },
     init() {
-      console.log("初始化");
       this.bmData = {};
       this.getDefaultData();
       this.imageList = {};

+ 61 - 12
src/components/pages/classroomObservation/index.vue

@@ -420,7 +420,7 @@ export default {
                     this.$nextTick(() => {
                       this.getCourseList().then(_ => {
                         this.getFileIdId();
-                        this.$refs.messageAreaRef.getData().then(res => {
+                        this.$refs.messageAreaRef.getData(tagList?tagList.dialogTagList:[]).then(res => {
                           if (tagList) {
                             this.$refs.messageAreaRef.changeAnalysisName(
                               tagList.dialogTagList,
@@ -732,10 +732,12 @@ export default {
           let canvas = document.createElement("canvas");
           let ctx = canvas.getContext("2d");
           canvas.width = 600 * window.devicePixelRatio;
-          canvas.height = 150 * window.devicePixelRatio;
+          canvas.height = 200 * window.devicePixelRatio;
           // 缩放绘图上下文
           ctx.scale(1, 1);
+
           let canvasWidth = canvas.width;
+          let canvasWidth2 = canvasWidth - 20;
           let canvasHeight = canvas.height;
           ctx.imageSmoothingEnabled = false;
           ctx.lineWidth = 1;
@@ -746,7 +748,7 @@ export default {
           const fontSize = 14; //字体大小
 
           ctx.fillStyle = teacherColor;
-          this.drawRoundedRect(ctx, 0, canvasHeight - 20, 20, 15, 5);
+          this.drawRoundedRect(ctx, 0, canvasHeight - 20, 20, 15, 4);
           // ctx.fillRect(0, canvasHeight - 20, 25, 20);
           ctx.fillStyle = "black";
           ctx.font = `${fontSize}px serif`;
@@ -754,21 +756,20 @@ export default {
 
           ctx.fillStyle = studentColor;
           // ctx.fillRect(100, canvasHeight - 20, 25, 20);
-          this.drawRoundedRect(ctx, 100, canvasHeight - 20, 20, 15, 5);
+          this.drawRoundedRect(ctx, 100, canvasHeight - 20, 20, 15, 4);
           ctx.fillStyle = "black";
           ctx.font = `${fontSize}px serif`;
           ctx.fillText("学生", 128, canvasHeight - 7);
           let sum = data.data.reduce((pre, cur) => (pre += cur.value), 0);
-
           // 当前x位置的起始点
-          let currentX = 0;
+          let currentX = 10;
           // 计算并绘制每个区域
           data.data.forEach(i => {
             const segmentWidth = parseFloat(
-              (i.value / (sum / canvasWidth)).toFixed(2)
+              (i.value / (sum / canvasWidth2)).toFixed(2)
             );
             ctx.fillStyle = i.type == 0 ? teacherColor : studentColor;
-            ctx.fillRect(currentX, 20, segmentWidth, canvasHeight - 60);
+            ctx.fillRect(currentX, 20, segmentWidth, canvasHeight - 100);
 
             // 更新x位置
             currentX += segmentWidth;
@@ -780,19 +781,45 @@ export default {
 
           data.breakpoint.forEach(i => {
             const breakpointPo = parseFloat(
-              (i / (sum / canvasWidth)).toFixed(2)
+              (i / (sum / canvasWidth2)).toFixed(2)
             );
             ctx.beginPath();
-            ctx.moveTo(breakpointPo, 0);
-            ctx.lineTo(breakpointPo, canvasHeight - 20);
+            ctx.moveTo(breakpointPo, 10);
+            ctx.lineTo(breakpointPo, canvasHeight - 70);
             ctx.stroke();
           });
 
+          let interval = parseFloat((300 / (sum / canvasWidth2)).toFixed(2));
+          //绘制竖线
+          for (let i = 0; i < canvasWidth2; i += interval) {
+            ctx.beginPath();
+            ctx.strokeStyle = "#BFBFBF";
+            ctx.moveTo(i == 0 ? 10 : i, canvasHeight - 70);
+            ctx.lineTo(i == 0 ? 10 : i, canvasHeight - 55);
+            ctx.stroke();
+            ctx.fillStyle = "#868686";
+            let timeLabel = (((i / canvasWidth2) * sum) / 60).toFixed(0); // 时间标识计算
+            ctx.font = `${fontSize}px serif`;
+            if (i == 0) {
+              ctx.fillText(`${timeLabel}min`, i + 10, canvasHeight - 40);
+            } else if (i + interval > canvasWidth2) {
+              ctx.fillText(`${timeLabel}min`, i - 20, canvasHeight - 40);
+            } else {
+              ctx.fillText(`${timeLabel}min`, i - 15, canvasHeight - 40);
+            }
+          }
+
+          ctx.beginPath();
+          ctx.strokeStyle = "#BFBFBF";
+          ctx.moveTo(10, canvasHeight - 55);
+          ctx.lineTo(canvasWidth2 + 10, canvasHeight - 55);
+          ctx.stroke();
+
           // 将 canvas 转换为 base64 格式的图片地址
           const base64Image = canvas.toDataURL("image/png");
           resolve(base64Image);
         } catch (e) {
-					console.log(e)
+          console.log(e);
           resolve("#");
         }
       });
@@ -1147,6 +1174,28 @@ export default {
     //保存词频词汇分析
     saveWordFrequency({ _sentence = 0, _words = 0 }) {
       this.$refs.messageAreaRef.saveWordFrequency({ _sentence, _words });
+    },
+    formatTime(seconds) {
+      let h = Math.floor(seconds / 3600); // 小时
+      let m = Math.floor((seconds % 3600) / 60); // 分钟
+      let s = Math.floor(seconds % 60); // 秒数
+
+      // 格式化为两位数
+      let formattedTime;
+      if (h > 0) {
+        // 如果有小时部分,格式化为 hh:mm:ss
+        formattedTime = `${h
+          .toString()
+          .padStart(2, "0")}:${m
+          .toString()
+          .padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
+      } else {
+        // 否则,格式化为 mm:ss
+        formattedTime = `${m
+          .toString()
+          .padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
+      }
+      return formattedTime;
     }
   },
   mounted() {