Browse Source

课堂观察

SanHQin 2 months ago
parent
commit
8a35ddc675
1 changed files with 284 additions and 211 deletions
  1. 284 211
      src/components/pages/classroomObservation/tools/mixin.js

+ 284 - 211
src/components/pages/classroomObservation/tools/mixin.js

@@ -19,8 +19,8 @@ import "echarts-wordcloud";
 import htmlDocx from "html-docx-js/dist/html-docx";
 
 export const toolMixin = {
-  data(){
-    return{
+  data() {
+    return {
       tag: {
         0: "一",
         1: "二",
@@ -174,12 +174,13 @@ ${arr.map(row => `<tr>
         if (fileData.fileObj) {
           _file = fileData.fileObj
         } else if (fileData.url) {
+          console.log("需要下载文件")
           let videoRes = await this.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: 2,err:"未找到文件" })
+        if (!_file) return resolve({ data: 2, err: "未找到文件" })
         console.log("需要处理的文件👉", _file)
         try {
           const reader = new FileReader();
@@ -191,9 +192,44 @@ ${arr.map(row => `<tr>
               //解码音频数据
               const buffer = await audioContext.decodeAudioData(e.target.result);
 
+              // 目标采样率和声道数
+              const targetSampleRate = 22050; // 你也可以设置 22050 或 32000,数值越低文件越小
+              const targetChannels = 1; // 单声道
+              // 计算新的缓冲长度
+              const newLength = Math.floor(buffer.duration * targetSampleRate);
+
               //创建离线音频上下文
               const offlineAudioContext = new OfflineAudioContext({ numberOfChannels: buffer.numberOfChannels, length: buffer.length, sampleRate: buffer.sampleRate });
 
+              // 创建缓冲区
+              const newBuffer = offlineAudioContext.createBuffer(
+                targetChannels,
+                newLength,
+                targetSampleRate
+              );
+
+              // 把原始 buffer 的数据转换并复制到新的 buffer(立体声混合到单声道)
+              for (let channel = 0; channel < targetChannels; channel++) {
+                const outputData = newBuffer.getChannelData(channel);
+                const inputDataLeft = buffer.numberOfChannels > 0 ? buffer.getChannelData(0) : null;
+                const inputDataRight = buffer.numberOfChannels > 1 ? buffer.getChannelData(1) : null;
+
+                for (let i = 0; i < newLength; i++) {
+                  // 计算对应原始采样点索引
+                  const origIndex = Math.floor(i * (buffer.sampleRate / targetSampleRate));
+
+                  // 立体声转单声道:左右声道取平均
+                  let sample = 0;
+                  if (inputDataLeft && inputDataRight) {
+                    sample = (inputDataLeft[origIndex] + inputDataRight[origIndex]) / 2;
+                  } else if (inputDataLeft) {
+                    sample = inputDataLeft[origIndex];
+                  }
+                  outputData[i] = sample;
+                }
+              }
+
+
               //创建音源节点
               const source = offlineAudioContext.createBufferSource();
               source.buffer = buffer;
@@ -206,19 +242,22 @@ ${arr.map(row => `<tr>
 
               // blob转成file文件
               const audioFile = new File([wavBlob], 'audio.wav', { type: 'audio/wav' });
+
+              console.log("需要上传的文件", audioFile)
               this.uploadFileMixin(audioFile).then(upload => {
+                console.log("upload=>",upload)
                 resolve({ audioUrl: upload, fileObj: audioFile })
               })
             } catch (error) {
               console.log("👉", error);
-              return resolve({ data: 2,err:error })
+              return resolve({ data: 2, err: error })
             }
 
           }
           reader.readAsArrayBuffer(_file);
         } catch (error) {
           console.log("👉", error);
-          return resolve({ data: 2,err:error })
+          return resolve({ data: 2, err: error })
         }
       })
     },
@@ -386,7 +425,7 @@ ${arr.map(row => `<tr>
             } else if (assistantData.id == "bfe844b1-7a45-11ef-9b30-005056b86db5") {//课堂活动光谱图
 
               let resultData = await this.getSpectrogram(_result, fileId, content, assistantData)
-              console.log("管谱图数据",resultData)
+              console.log("管谱图数据", resultData)
               if (resultData.message) analysisData.content = resultData.message;
               if (resultData.eCharts) analysisData.spectrogramData = resultData.eCharts;
               return resolve({ data: analysisData })
@@ -985,7 +1024,7 @@ CH:${_CH}
             let upTime = '00:00:00';
 
             _dataList.forEach((item, index) => {
-              if(!item.role)return;
+              if (!item.role) return;
               if (index == 0) {
                 //第一个
                 identity = item.role;
@@ -1052,7 +1091,7 @@ CH:${_CH}
 
           });
         } catch (e) {
-          console.log("光谱生成失败",e)
+          console.log("光谱生成失败", e)
           return resolve({ data: 1, err: e })
         }
       })
@@ -1216,9 +1255,9 @@ CH:${_CH}
 
         let timer = null;
 
-        timer = setTimeout(()=>{//五分钟无响应就算报错
-          resolve({ data: 1,transcriptionContent:null,editorBarData:null,err: "转录超时" })
-        },180000)
+        timer = setTimeout(() => {//五分钟无响应就算报错
+          resolve({ data: 1, transcriptionContent: null, editorBarData: null, err: "转录超时" })
+        }, 180000)
 
         // 转录中
         iframeRef.contentWindow.onRecognizedResult = (e) => {
@@ -1227,11 +1266,11 @@ CH:${_CH}
           let privDuration = e.privDuration;
           let privOffset = e.privOffset;
 
-          if(timer){
+          if (timer) {
             clearTimeout(timer)
-            timer = setTimeout(()=>{//五分钟无响应就算报错
-              resolve({ data: 1,transcriptionContent:null,editorBarData:null,err: "转录超时" })
-            },180000)
+            timer = setTimeout(() => {//五分钟无响应就算报错
+              resolve({ data: 1, transcriptionContent: null, editorBarData: null, err: "转录超时" })
+            }, 180000)
           }
           if (!privText || !privSpeakerId || privSpeakerId == "Unknown") {//不记录
             return;
@@ -1254,7 +1293,7 @@ CH:${_CH}
 
         //转录结束
         iframeRef.contentWindow.onSessionStopped = async (e) => {
-          if(timer){
+          if (timer) {
             clearTimeout(timer)
           }
           tableContent = `<table
@@ -1486,7 +1525,7 @@ CH:${_CH}
 
         console.log("说话人身份编码开始")
         // 说话人身份编码
-        while (tableList.some(i => i.role == '' &&  i.value != "" && i.index !=="")) {
+        while (tableList.some(i => i.role == '' && i.value != "" && i.index !== "")) {
           let _ajaxList = tableList.filter(i => i.role == '').slice(0, 10);
           console.log(`说话人身份编码:`, _ajaxList)
           const params = {
@@ -1554,7 +1593,7 @@ CH:${_CH}
         }
         console.log("说话人身份编码完成")
 
-        console.log("allRole",tableList.map(i=>i.role))
+        console.log("allRole", tableList.map(i => i.role))
 
         console.log("说话人行为编码开始")
         //说话人行为编码
@@ -1590,7 +1629,7 @@ CH:${_CH}
         console.log("说话人行为编码完成")
 
         tableList.forEach((item, index) => {
-          if(item.value=="")return;
+          if (item.value == "") return;
           tableContent += `<tr>
           <td>${index + 1}</td>
           <td>${item.startTime}</td>
@@ -1646,7 +1685,7 @@ CH:${_CH}
 
         const reader = new FileReader();
 
-        reader.onload = (e)=>{
+        reader.onload = (e) => {
           const arrayBuffer = e.target.result;
 
           // 解码音频数据
@@ -1693,48 +1732,48 @@ CH:${_CH}
       return new Promise(resolve => {
         try {
           let hiddenDiv = document.createElement("div");
-        hiddenDiv.style.width = "600px";
-        hiddenDiv.style.height = "400px";
-        hiddenDiv.style.position = "absolute";
-        hiddenDiv.style.left = "-9999px"; // 隐藏div
-        document.body.appendChild(hiddenDiv);
-
-        // 初始化图表
-        let myChart = echarts.init(hiddenDiv);
-
-       console.log(option)
-       option.animation = false;
-
-       let time;
-        myChart.on("rendered", async () => {
-          // console.log("生成echarts成功")
-          // 获取图表的图片
-
-          clearTimeout(time)
-          time = setTimeout(()=>{
-            let base64Image = myChart.getDataURL({
-              type: "png", // 图片格式
-              pixelRatio: 0.9, // 图像清晰度
-              backgroundColor: "#fff" // 背景颜色
-            });
+          hiddenDiv.style.width = "600px";
+          hiddenDiv.style.height = "400px";
+          hiddenDiv.style.position = "absolute";
+          hiddenDiv.style.left = "-9999px"; // 隐藏div
+          document.body.appendChild(hiddenDiv);
+
+          // 初始化图表
+          let myChart = echarts.init(hiddenDiv);
+
+          console.log(option)
+          option.animation = false;
+
+          let time;
+          myChart.on("rendered", async () => {
+            // console.log("生成echarts成功")
+            // 获取图表的图片
+
+            clearTimeout(time)
+            time = setTimeout(() => {
+              let base64Image = myChart.getDataURL({
+                type: "png", // 图片格式
+                pixelRatio: 0.9, // 图像清晰度
+                backgroundColor: "#fff" // 背景颜色
+              });
 
-            resolve(base64Image);
-            // 清除隐藏的div和图表实例
-            document.body.removeChild(hiddenDiv);
-            myChart.dispose();
-          },200)
+              resolve(base64Image);
+              // 清除隐藏的div和图表实例
+              document.body.removeChild(hiddenDiv);
+              myChart.dispose();
+            }, 200)
 
-        }).on("error", (error) => {
-          console.log("生成echarts失败",error)
-          resolve("#")
-        });
+          }).on("error", (error) => {
+            console.log("生成echarts失败", error)
+            resolve("#")
+          });
 
-        // 设置图标配置
-        myChart.setOption(option);
+          // 设置图标配置
+          myChart.setOption(option);
           // console.log("词云图???",option)
 
         } catch (error) {
-          console.log(error,"error")
+          console.log(error, "error")
           resolve("#")
         }
       });
@@ -1842,7 +1881,7 @@ CH:${_CH}
             }
             _lastI = i;
           }
-          if (canvasWidth2 - _lastI >60) {
+          if (canvasWidth2 - _lastI > 60) {
             ctx.beginPath();
             ctx.strokeStyle = "#BFBFBF";
             ctx.moveTo(canvasWidth2 + 10, canvasHeight - 70);
@@ -1889,9 +1928,9 @@ CH:${_CH}
           img.onload = () => {
             ctx.drawImage(img, 0, 0, canvasWidth, canvasWidth);
             ctx.beginPath();
-            let _showWidth = canvasWidth-((canvasWidth/8.8)*2)
+            let _showWidth = canvasWidth - ((canvasWidth / 8.8) * 2)
             ctx.fillStyle = fontColor;
-            ctx.arc((canvasWidth/8.8)+(_showWidth*parseFloat(data.RT)),(canvasWidth/8.8)+_showWidth-(_showWidth*parseFloat(data.CH)),4,0,2*Math.PI);
+            ctx.arc((canvasWidth / 8.8) + (_showWidth * parseFloat(data.RT)), (canvasWidth / 8.8) + _showWidth - (_showWidth * parseFloat(data.CH)), 4, 0, 2 * Math.PI);
             ctx.lineWidth = 0.5; // 设置边框大小
             // ctx.arc((canvasWidth*parseFloat(this.data.RT))+(canvasWidth/8.8),(canvasWidth-(canvasWidth*parseFloat(this.data.CH))+(canvasWidth/8.8)), 4, 0, 2 * Math.PI);
             ctx.fill();
@@ -1932,130 +1971,125 @@ CH:${_CH}
       ctx.closePath();
       ctx.fill(); // 填充颜色
     },
-    getDocFnPromise(task){
-      console.log("处理👉",task)
-      return new Promise(async (resolve)=>{
+    getDocFnPromise(task) {
+      console.log("处理👉", task)
+      return new Promise(async (resolve) => {
         try {
           let bmData = task.jsonData.baseMessage;
-        const md = new markdownIt();
-        let dataList = task.jsonData.analysisList;
-        let tagList = task.jsonData.tagList?task.jsonData.tagList:[
-          { value: 0, name: "通用课堂分析", loading: false },
-          { value: 1, name: "学科课堂分析", loading: false },
-          { value: 2, name: "扩展分析", loading: false }
-        ];
-        let showBrief = true;
-
-        // console.log(tagList,"tagList")
-
-        tagList.forEach(i => (i.dataList = []));
-        let url = `https://beta.cloud.cocorobo.cn/aigpt/#/classroom_observation_board?tid=${task.jsonData.createId}`;
-        const qRCodeSrc = await this.getQrCodeImageSrc(url);
-
-        dataList.sort((a, b) => a.tIndex - b.tIndex);
-        dataList.forEach(i1 => {
-          tagList.forEach(i2 => {
-            if (i2.value == i1.Type) {
-              i2.dataList.push(i1);
-            }
+          const md = new markdownIt();
+          let dataList = task.jsonData.analysisList;
+          let tagList = task.jsonData.tagList ? task.jsonData.tagList : [
+            { value: 0, name: "通用课堂分析", loading: false },
+            { value: 1, name: "学科课堂分析", loading: false },
+            { value: 2, name: "扩展分析", loading: false }
+          ];
+          let showBrief = true;
+
+          // console.log(tagList,"tagList")
+
+          tagList.forEach(i => (i.dataList = []));
+          let url = `https://beta.cloud.cocorobo.cn/aigpt/#/classroom_observation_board?tid=${task.jsonData.createId}`;
+          const qRCodeSrc = await this.getQrCodeImageSrc(url);
+
+          dataList.sort((a, b) => a.tIndex - b.tIndex);
+          dataList.forEach(i1 => {
+            tagList.forEach(i2 => {
+              if (i2.value == i1.Type) {
+                i2.dataList.push(i1);
+              }
+            });
           });
-        });
 
-        let directoryHtml = `<div style="margin-bottom:1in"><div style="text-align:center;font-size:20pt;margin-bottom:0.5in">目录</div>`;
+          let directoryHtml = `<div style="margin-bottom:1in"><div style="text-align:center;font-size:20pt;margin-bottom:0.5in">目录</div>`;
 
-        let analysisHtml = ``;
+          let analysisHtml = ``;
 
-        // console.log("开始处理文件")
-        for (let c = 0; c < tagList.length; c++) {
-          // console.log(tagList[c],"tagList[c]")
-          let i = tagList[c];
-          let dire = `<div>`;
-          let tagHtml = `<div style="margin-bottom:0.5in">`;
-          if (i.value == 0) {
-            i.dataList = i.dataList.filter(i2 => i2.tIndex != 2);
-          }
-          i.dataList.sort((a, b) => a.tIndex - b.tIndex);
-          tagHtml += `<h1 style="font-size:16pt;margin-bottom:-1in">${
-            this.tag[i.value]
-          }、${i.name}</h1>`;
-          dire += `<p style="font-size:14pt;margin-bottom:-0.8in">${
-            this.tag[i.value]
-          }、${i.name}</p>`;
-
-          for (let d = 0; d < i.dataList.length; d++) {
-            let i2 = i.dataList[d];
-            // console.log(i.dataList[d],"i.dataList[d]")
-            let i2Index = d;
-            tagHtml += `<h2 style="font-size:14pt;margin-bottom:-1in">${i2Index +
-              1}、${
-              i2.jsonData.anotherName
-                ? i2.jsonData.anotherName
-                : i2.jsonData.name
-            }</h2>`;
-            dire += `<p style="font-size:11pt;margin-bottom:-0.8in;margin-left:0.1in">${i2Index +
-              1}、${
-              i2.jsonData.anotherName
-                ? i2.jsonData.anotherName
-                : i2.jsonData.name
-            }</p>`;
-            if (showBrief && i2.jsonData.result) {
-              tagHtml += `<p style="font-size:10.5pt;font-style:italic;margin-bottom:-0.7in;color:#6b798e">${i2.jsonData.result}</p>`;
-            }
-            if (i2.jsonData.eChartData) {
-              // console.log("处理i2.jsonData.eChartData",i2.jsonData)
-              tagHtml += `<div style="width:100vw;padding:70%;box-sizing: border-box;text-align:center"><img style="margin:auto" src="${await this.getEChartsImageSrc(
-                i2.jsonData.eChartData
-              )}"/></div>`;
+          // console.log("开始处理文件")
+          for (let c = 0; c < tagList.length; c++) {
+            // console.log(tagList[c],"tagList[c]")
+            let i = tagList[c];
+            let dire = `<div>`;
+            let tagHtml = `<div style="margin-bottom:0.5in">`;
+            if (i.value == 0) {
+              i.dataList = i.dataList.filter(i2 => i2.tIndex != 2);
             }
+            i.dataList.sort((a, b) => a.tIndex - b.tIndex);
+            tagHtml += `<h1 style="font-size:16pt;margin-bottom:-1in">${this.tag[i.value]
+              }、${i.name}</h1>`;
+            dire += `<p style="font-size:14pt;margin-bottom:-0.8in">${this.tag[i.value]
+              }、${i.name}</p>`;
+
+            for (let d = 0; d < i.dataList.length; d++) {
+              let i2 = i.dataList[d];
+              // console.log(i.dataList[d],"i.dataList[d]")
+              let i2Index = d;
+              tagHtml += `<h2 style="font-size:14pt;margin-bottom:-1in">${i2Index +
+                1}、${i2.jsonData.anotherName
+                  ? i2.jsonData.anotherName
+                  : i2.jsonData.name
+                }</h2>`;
+              dire += `<p style="font-size:11pt;margin-bottom:-0.8in;margin-left:0.1in">${i2Index +
+                1}、${i2.jsonData.anotherName
+                  ? i2.jsonData.anotherName
+                  : i2.jsonData.name
+                }</p>`;
+              if (showBrief && i2.jsonData.result) {
+                tagHtml += `<p style="font-size:10.5pt;font-style:italic;margin-bottom:-0.7in;color:#6b798e">${i2.jsonData.result}</p>`;
+              }
+              if (i2.jsonData.eChartData) {
+                // console.log("处理i2.jsonData.eChartData",i2.jsonData)
+                tagHtml += `<div style="width:100vw;padding:70%;box-sizing: border-box;text-align:center"><img style="margin:auto" src="${await this.getEChartsImageSrc(
+                  i2.jsonData.eChartData
+                )}"/></div>`;
+              }
 
-            if (i2.jsonData.spectrogramData) {
-              // console.log("处理i2.jsonData.spectrogramData",i2.jsonData)
-              tagHtml += `<div style="width:100vw;padding:70%;box-sizing: border-box;text-align:center"><img style="margin:auto" src="${await this.getEChartsSpectrogramImage(
-                i2.jsonData.spectrogramData
-              )}"/></div>`;
-              // console.log()
-            }
+              if (i2.jsonData.spectrogramData) {
+                // console.log("处理i2.jsonData.spectrogramData",i2.jsonData)
+                tagHtml += `<div style="width:100vw;padding:70%;box-sizing: border-box;text-align:center"><img style="margin:auto" src="${await this.getEChartsSpectrogramImage(
+                  i2.jsonData.spectrogramData
+                )}"/></div>`;
+                // console.log()
+              }
 
-            if (i2.jsonData.CH && i2.jsonData.RT) {
-              // console.log("处理i2.jsonData.CHRT",i2.jsonData)
-              tagHtml += `<div style="width:100vw;text-align:center;padding:70%;box-sizing: border-box;"><img style="margin:auto" src="${await this.getEChartsechartsRTCHImage(
-                {
-                  RT: i2.jsonData.RT,
-                  CH: i2.jsonData.CH
-                }
-              )}"/></div>`;
-            }
+              if (i2.jsonData.CH && i2.jsonData.RT) {
+                // console.log("处理i2.jsonData.CHRT",i2.jsonData)
+                tagHtml += `<div style="width:100vw;text-align:center;padding:70%;box-sizing: border-box;"><img style="margin:auto" src="${await this.getEChartsechartsRTCHImage(
+                  {
+                    RT: i2.jsonData.RT,
+                    CH: i2.jsonData.CH
+                  }
+                )}"/></div>`;
+              }
 
-            let _content = md.render(i2.jsonData.content).replace(/<p>/g, '').replace(/<\/p>/g, '').replace(/<strong>/g, '<span style="font-weight: bold;">').replace(/<\/strong>/g, '</span>');
-            tagHtml += `<p style="font-size:10.5pt;margin-bottom:-0.5in">${_content}</p>`;
+              let _content = this.processHtml(md.render(i2.jsonData.content).replace(/<p>/g, '').replace(/<\/p>/g, '').replace(/<strong>/g, '<span style="font-weight: bold;">').replace(/<\/strong>/g, '</span>'));
+              tagHtml += `<p style="font-size:10.5pt;margin-bottom:-0.5in">${_content}</p>`;
+            }
+            tagHtml += "</div>";
+            dire += "</div>";
+            analysisHtml += tagHtml;
+            directoryHtml += dire;
           }
-          tagHtml += "</div>";
-          dire += "</div>";
-          analysisHtml += tagHtml;
-          directoryHtml += dire;
-        }
 
-        // console.log("处理分析完成")
-        directoryHtml += "</div>";
-        let _html = `
+
+          console.log("analysisHtml", analysisHtml)
+          // return
+          // console.log("处理分析完成")
+          directoryHtml += "</div>";
+          let _html = `
 			      <div>
 			      	<p style="width:100vw;margin-bottom:1.5in">*分析结果仅供参考</p>
 			      	<p style="font-size:28pt;width:100vw;text-align:center;">课堂观察报告</p>
 			      	<p style="font-size:10pt;width:100vw;text-align:center;margin-bottom:0.6in">报告生成时间:${new Date().toLocaleString()}</p>
 			      	<div style="font-size:16pt;width:100vw;text-align:center;margin-bottom:1in">
 			      		<p style="font-size:20pt;margin-bottom:0.7in">《${bmData.courseName}》</p>
-			      		<p style="margin-bottom:-1in">授课老师:${
-                  bmData.teacherName ? bmData.teacherName : "未填写"
-                }</p>
-			      		<p style="margin-bottom:-1in">授课年级:${
-                  bmData.grade ? bmData.grade : "未填写"
-                }</p>
-			      		<p style="margin-bottom:-1in">授课科目:${
-                  bmData.subject ? bmData.subject : "未填写"
-                }</p>
-			      		<p style="margin-bottom:-1in">授课时间:${
-                  bmData.time ? bmData.time : "未填写"
-                }</p>
+			      		<p style="margin-bottom:-1in">授课老师:${bmData.teacherName ? bmData.teacherName : "未填写"
+            }</p>
+			      		<p style="margin-bottom:-1in">授课年级:${bmData.grade ? bmData.grade : "未填写"
+            }</p>
+			      		<p style="margin-bottom:-1in">授课科目:${bmData.subject ? bmData.subject : "未填写"
+            }</p>
+			      		<p style="margin-bottom:-1in">授课时间:${bmData.time ? bmData.time : "未填写"
+            }</p>
 			      	</div>
 			      	<div style="font-size:16pt;width:100vw;text-align:center;margin-bottom:0.5in">
 			      		<img src="${qRCodeSrc}" style="width:150px;height:150px;margin:auto;"/>
@@ -2069,7 +2103,7 @@ CH:${_CH}
 			      </div>
 			      `;
 
-            const content = `<!DOCTYPE html>
+          const content = `<!DOCTYPE html>
             <html xmlns:v='urn:schemas-microsoft-com
             :vml'xmlns:o='urn:schemas-microsoft-com:office
             :office'xmlns:w='urn:schemas-microsoft-com:office
@@ -2138,23 +2172,23 @@ CH:${_CH}
           });
           resolve(file)
         } catch (error) {
-          console.log("error",error,task)
+          console.log("error", error, task)
           resolve(error)
         }
       })
     },
-    getFileLastUpdateTime(file){
+    getFileLastUpdateTime(file) {
       console.log(file)
-      if(!file)return new Date().toLocaleDateString().replaceAll("/","-") + ' ' + new Date().toLocaleTimeString();
+      if (!file) return new Date().toLocaleDateString().replaceAll("/", "-") + ' ' + new Date().toLocaleTimeString();
 
-      const lastModifiedTimestamp  = file.lastModified;
-      console.log("lastModifiedTimestamp",lastModifiedTimestamp)
-      if(!lastModifiedTimestamp)return new Date().toLocaleDateString().replaceAll("/","-") + ' ' + new Date().toLocaleTimeString();
-      else return new Date(lastModifiedTimestamp).toLocaleDateString().replaceAll("/","-") + ' ' + new Date().toLocaleTimeString();
+      const lastModifiedTimestamp = file.lastModified;
+      console.log("lastModifiedTimestamp", lastModifiedTimestamp)
+      if (!lastModifiedTimestamp) return new Date().toLocaleDateString().replaceAll("/", "-") + ' ' + new Date().toLocaleTimeString();
+      else return new Date(lastModifiedTimestamp).toLocaleDateString().replaceAll("/", "-") + ' ' + new Date().toLocaleTimeString();
     },
     //获取词云图
-    getWordCloudMapMixin(data){
-      return new Promise((resolve)=>{
+    getWordCloudMapMixin(data) {
+      return new Promise((resolve) => {
         const _msg = `NOTICE
         Language: Please use the same language as the user requirement, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
         ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
@@ -2207,26 +2241,26 @@ CH:${_CH}
         `;
 
         const _uuid = uuidv4();
-				let params = {
-					temperature: 0,
-					max_tokens: 4096,
-					top_p: 1,
-					frequency_penalty: 0,
-					presence_penalty: 0,
-					messages: [{ role: "user", content: _msg }],
-					uid: _uuid,
-					mind_map_question: "",
-					stream: false,
-					model: "gpt-4o-2024-11-20",
-				};
+        let params = {
+          temperature: 0,
+          max_tokens: 4096,
+          top_p: 1,
+          frequency_penalty: 0,
+          presence_penalty: 0,
+          messages: [{ role: "user", content: _msg }],
+          uid: _uuid,
+          mind_map_question: "",
+          stream: false,
+          model: "gpt-4o-2024-11-20",
+        };
 
         this.ajax
-					.post("https://gpt4.cocorobo.cn/chat", params)
-					.then((res) => {
-						let _data = res.data.FunctionResponse.choices[0];
-						let _jsonData = _data.message.content;
-						_jsonData = _jsonData.replaceAll("```json", "").replaceAll("```", "");
-						let _result = JSON.parse(_jsonData);
+          .post("https://gpt4.cocorobo.cn/chat", params)
+          .then((res) => {
+            let _data = res.data.FunctionResponse.choices[0];
+            let _jsonData = _data.message.content;
+            _jsonData = _jsonData.replaceAll("```json", "").replaceAll("```", "");
+            let _result = JSON.parse(_jsonData);
             resolve({
               tooltip: {
                 show: false,
@@ -2236,7 +2270,7 @@ CH:${_CH}
                   type: 'wordCloud',
                   sizeRange: [14, 38],
                   rotationRange: [0, 0],
-                  keepAspect:false,
+                  keepAspect: false,
                   shape: 'circle',
                   left: 'center',
                   top: 'center',
@@ -2251,33 +2285,72 @@ CH:${_CH}
               ],
             })
           })
-					.catch((e) => {
-						console.log(e);
-						resolve(0)
+          .catch((e) => {
+            console.log(e);
+            resolve(0)
 
-					})
+          })
 
       })
     },
     //删除课堂
-    deleteClassMixin(tid){
-      return new Promise((resolve)=>{
+    deleteClassMixin(tid) {
+      return new Promise((resolve) => {
         let params = {
-          tid:tid
+          tid: tid
         }
         this.ajax
-        .post(
-          "https://gpt4.cocorobo.cn/update_classroom_observation_isdel",
-          params
-        )
-        .then(res => {
-          resolve(1)
-        }).catch(err=>{
-          console.log(err);
-          resolve(0)
-        })
+          .post(
+            "https://gpt4.cocorobo.cn/update_classroom_observation_isdel",
+            params
+          )
+          .then(res => {
+            resolve(1)
+          }).catch(err => {
+            console.log(err);
+            resolve(0)
+          })
 
       })
     },
+    //li里加上div
+    processHtml(html) {
+      // 1. 先把 li 里的 ol 结构替换掉
+      html = html.replace(/<li>\s*<ol[^>]*>\s*<li>([\s\S]*?)<\/li>\s*<\/ol>\s*<\/li>/g, (match, content) => {
+        return `<li>\n${content.trim()}\n</li>`;
+      });
+
+      // 2. 给 li 里的内容按行加 br
+      html = html.replace(/<li>([\s\S]*?)<\/li>/g, (match, content) => {
+        const lines = content
+          .trim()
+          .split(/(?:\r?\n)+/)
+          .map(line => line.trim())
+          .filter(line => line); // 过滤空行
+
+        if (lines.length <= 1) {
+          return `<li>\n${lines.join('')}\n</li>`;
+        } else {
+          return `<li>\n${lines.join('<br>\n')}\n</li>`;
+        }
+      });
+
+      // 3. 处理 pre 里的换行
+      html = html.replace(/<pre>([\s\S]*?)<\/pre>/g, (match, content) => {
+        const lines = content
+          .trim()
+          .split(/(?:\r?\n)+/)
+          .map(line => line.trim())
+          .filter(line => line); // 过滤空行
+
+        if (lines.length <= 1) {
+          return `<pre>${lines.join('')}</pre>`;
+        } else {
+          return `<pre>${lines.join('<br>\n')}</pre>`;
+        }
+      });
+
+      return html;
+    }
   }
 };