Browse Source

Merge branch 'beta'

qgt 1 month ago
parent
commit
512317e361

+ 1 - 1
dist/index.html

@@ -32,7 +32,7 @@
       width: 100%;
       background: #e6eaf0;
       font-family: '黑体';
-    }</style><link href=./static/css/app.69fc29f3fdc3eb01d41b01d8f4bfc7fc.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.23ea04dc469b57e2b4f8.js></script><script type=text/javascript src=./static/js/vendor.dfc8a8e3392292c7b8e5.js></script><script type=text/javascript src=./static/js/app.8f84b0b687bca50a7b90.js></script></body></html><script>function stopSafari() {
+    }</style><link href=./static/css/app.d20d59ebd2d033eec209ecb5a7031fb2.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.13ce8e475898fba4b86d.js></script><script type=text/javascript src=./static/js/vendor.715d92365c85ab803f65.js></script><script type=text/javascript src=./static/js/app.30eebf9fec06c84113c8.js></script></body></html><script>function stopSafari() {
     //阻止safari浏览器双击放大功能
     let lastTouchEnd = 0  //更新手指弹起的时间
     document.documentElement.addEventListener("touchstart", function (event) {

File diff suppressed because it is too large
+ 0 - 0
dist/static/css/app.d20d59ebd2d033eec209ecb5a7031fb2.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/app.d20d59ebd2d033eec209ecb5a7031fb2.css.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/0.9f2408d57b212f100e92.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/0.9f2408d57b212f100e92.js.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/0.eb6bdee5e7207bfd76b0.js.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/app.30eebf9fec06c84113c8.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/app.30eebf9fec06c84113c8.js.map


+ 2 - 2
dist/static/js/manifest.23ea04dc469b57e2b4f8.js → dist/static/js/manifest.13ce8e475898fba4b86d.js

@@ -1,2 +1,2 @@
-!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={8: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:"eb6bdee5e7207bfd76b0",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.23ea04dc469b57e2b4f8.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={8: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:"9f2408d57b212f100e92",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.13ce8e475898fba4b86d.js.map

File diff suppressed because it is too large
+ 0 - 0
dist/static/js/manifest.13ce8e475898fba4b86d.js.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/vendor.715d92365c85ab803f65.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/vendor.715d92365c85ab803f65.js.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/workPage-manifest.2ece51fa34be51c8610a.js.map


+ 13 - 2
src/components/pages/classroomObservation/components/chatArea.vue

@@ -591,6 +591,7 @@ import addNewTeacherVoiceprintDialog from "./addNewTeacherVoiceprintDialog.vue";
 import * as Sy from "@/lib/shengyang";
 import Recorder from "recorder-core/recorder.mp3.min";
 import { fetchEventSource } from "@microsoft/fetch-event-source";
+import {mediaFileToWavFile} from '../tools/tools.js'
 // import { saveAs } from "file-saver";
 
 // import Recorder from 'recorder-core/recorder.wav.min'
@@ -845,7 +846,7 @@ export default {
       this.languageShow = !this.languageShow;
     },
     // 上传录音
-    uploadRecording() {
+    async uploadRecording() {
       if (!this.tid) {
         return this.$parent.addNewCourse().then(_ => {
           this.uploadRecording();
@@ -858,7 +859,7 @@ export default {
       // input.accept = "audio/*, .txt, .pdf, .xlsx";
       input.accept = ".m4a,.mp3,.wav,.txt,.pdf,.xlsx,.doc,.docx,.csv";
       input.click();
-      input.onchange = () => {
+      input.onchange = async () => {
         this.uploadFileLoading = true;
         let file = input.files[0];
         if (!/\.(m4a|mp3|wav|txt|pdf|xlsx|doc|docx|csv)$/i.test(file.name)) {
@@ -867,7 +868,17 @@ export default {
             "请上传.mp3,.wav,.txt,.pdf,.xlsx,.doc,.docx,.csv格式的文件"
           );
         }
+
+				// 判断如果是m4a文件
+        if (/\.m4a$/i.test(file.name)) {
+          file = await mediaFileToWavFile(file,{sampleRate:8000}) 
+        }
+
+
+				// return console.log("成熟市场",file)
+
         this.uploadFile(file, { changeText: true, flag: true });
+
         // this.uploadWavFileAndGetText(file);
       };
     },

+ 112 - 0
src/components/pages/classroomObservation/tools/tools.js

@@ -0,0 +1,112 @@
+const mediaFileToWavFile = async (mediaObj, options = {}) => {
+  let _file = null
+  // if (mediaObj.url) {
+  //   let res = await getFile(mediaObj.url)
+  //   if (res.data === 1) {
+  //     console.log('获取媒体文件失败')
+  //     return ''
+  //   }
+  //   _file = new File([res.data], mediaObj.name, { type: mediaObj.type })
+  // } else {
+    _file = mediaObj
+  // }
+
+  // 添加参数配置
+  const { sampleRate = 22050, optimize = false } = options
+  
+  return new Promise((resolve) => {
+    try {
+      const reader = new FileReader();
+      reader.onload = async (e) => {
+        const audioContext = new (window.AudioContext || window.webkitAudioContext)();
+        const buffer = await audioContext.decodeAudioData(e.target.result);
+        
+        let targetBuffer = buffer;
+        
+        // 如果启用优化或指定采样率
+        if (optimize || sampleRate !== buffer.sampleRate) {
+          const targetSampleRate = Math.min(sampleRate, buffer.sampleRate);
+          
+          const offlineAudioContext = new OfflineAudioContext({
+            numberOfChannels: buffer.numberOfChannels,
+            length: Math.floor(buffer.length * targetSampleRate / buffer.sampleRate),
+            sampleRate: targetSampleRate
+          });
+          
+          const source = offlineAudioContext.createBufferSource();
+          source.buffer = buffer;
+          source.connect(offlineAudioContext.destination);
+          source.start();
+          
+          targetBuffer = await offlineAudioContext.startRendering();
+        }
+        
+        const wavBlob = bufferToWav(targetBuffer);
+        const fileName = mediaObj.name ? 
+          mediaObj.name.replace(/\.[^/.]+$/, "") + '.wav' : 
+          'audio.wav';
+        const audioFile = new File([wavBlob], fileName, { type: 'audio/wav' });
+        
+        console.log(`转换成功,采样率: ${targetBuffer.sampleRate}Hz,文件大小: ${(audioFile.size / 1024 / 1024).toFixed(2)}MB`)
+        resolve(audioFile)
+      }
+      reader.readAsArrayBuffer(_file);
+    } catch (error) {
+      console.log('音频提取失败', error)
+      resolve('')
+    }
+  })
+}
+
+function bufferToWav(buffer) {
+  const numChannels = buffer.numberOfChannels;
+  const sampleRate = buffer.sampleRate;
+  const format = 1; // PCM
+  const bitDepth = 16;
+  
+  const bytesPerSample = bitDepth / 8;
+  const blockAlign = numChannels * bytesPerSample;
+  const byteRate = sampleRate * blockAlign;
+  const dataSize = buffer.length * blockAlign;
+  
+  const bufferLength = 44 + dataSize;
+  const arrayBuffer = new ArrayBuffer(bufferLength);
+  const view = new DataView(arrayBuffer);
+  
+  // WAV 头部
+  writeString(view, 0, 'RIFF');
+  view.setUint32(4, bufferLength - 8, true);
+  writeString(view, 8, 'WAVE');
+  writeString(view, 12, 'fmt ');
+  view.setUint32(16, 16, true); // fmt chunk size
+  view.setUint16(20, format, true);
+  view.setUint16(22, numChannels, true);
+  view.setUint32(24, sampleRate, true);
+  view.setUint32(28, byteRate, true);
+  view.setUint16(32, blockAlign, true);
+  view.setUint16(34, bitDepth, true);
+  writeString(view, 36, 'data');
+  view.setUint32(40, dataSize, true);
+  
+  // 写入 PCM 数据
+  let offset = 44;
+  for (let i = 0; i < buffer.length; i++) {
+    for (let channel = 0; channel < numChannels; channel++) {
+      const sample = Math.max(-1, Math.min(1, buffer.getChannelData(channel)[i]));
+      view.setInt16(offset, sample < 0 ? sample * 0x8000 : sample * 0x7FFF, true);
+      offset += 2;
+    }
+  }
+  
+  return new Blob([arrayBuffer], { type: 'audio/wav' });
+}
+
+function writeString(view, offset, string) {
+  for (let i = 0; i < string.length; i++) {
+    view.setUint8(offset + i, string.charCodeAt(i));
+  }
+}
+
+export {
+	mediaFileToWavFile
+}

+ 4 - 4
src/components/pages/course.vue

@@ -38,11 +38,11 @@
               <!-- <div type="primary" @click="goToCourse2()">任务式课程</div> -->
               <!-- <div type="primary" @click="goToCourse()">阶段式课程</div> -->
               <div type="primary" @click="goToCourse4()">阶段式课程</div>
+              <div type="primary" @click="goToPptEasy()" v-show="pptArrayOrg.includes(org) || pptArrayOid.includes(oid)">互动课件模式</div>
 
               <!-- v-show="org == '1973f6c7-1561-11ee-91d8-005056b86db5' || org == '777559d2-7239-11ee-b98c-005056b86db5' || org == '884c5665-a453-46f3-b7b6-01d575290aa9'" -->
-              <div type="primary" @click="oepnTemplate()" v-show="orgArray.includes(org) || oidArray.includes(oid)">AI模式</div>
-              <div type="primary" @click="oepnTemplate2()" v-show="orgArray.includes(org) || oidArray.includes(oid)">上课模式</div>
-              <div type="primary" @click="goToPptEasy()" v-show="pptArrayOrg.includes(org) || pptArrayOid.includes(oid)">PPT模式</div>
+              <div type="primary" @click="oepnTemplate()" v-show="orgArray.includes(org) || oidArray.includes(oid)">AI引导模式</div>
+              <div type="primary" @click="oepnTemplate2()" v-show="orgArray.includes(org) || oidArray.includes(oid)">解析教案模式</div>
               <!-- oepnTemplate2 -->
             </div>
           </button>
@@ -217,7 +217,7 @@
               <!-- v-if="item.isCourseType == 2 || groupA == 1" -->
               <div class="kc_t">
                 <span>{{ item.uname }}</span>
-                <span>{{ item.state == 1 ? '阶段模式' : item.state == 2 ? '任务模式' :  item.state == 3 ? '极简模式' : item.state == 6 ? '上课模式' : item.state == 7 ? 'PPT模式' : 'AI模式' }}</span>
+                <span>{{ item.state == 1 ? '阶段模式' : item.state == 2 ? '任务模式' :  item.state == 3 ? '极简模式' : item.state == 6 ? '解析教案模式' : item.state == 7 ? '互动课件模式' : 'AI引导模式' }}</span>
               </div>
               <div class="kc_time">
                 <span style="color: #717C8D">创建日期:</span>{{ item.time }}

+ 1 - 1
src/components/pages/synergyCourse/group/group.vue

@@ -611,7 +611,7 @@ export default {
                             }
                             this.islock = false
                             this.isopen = true
-                            this.$message.success(this.OperateSuccessful);
+                            this.$message.success(this.lang.OperateSuccessful);
                             this.getCourseGroup();
                             this.$forceUpdate()
                         })

+ 3 - 1
src/lang/cn.json

@@ -168,7 +168,7 @@
   "Joinsuccessfully":"加入成功",
   "unabletoexit":"位置已被锁定,无法退出",
   "exist":"在",
-  "SMARTPaste ":"智能粘贴",
+  "SMARTPaste":"智能粘贴",
   "uploadpictures":"上传图片",
   "Selectlocalfile":"选择本地文件",
   "Selectnetworkfiles":"选择网络文件",
@@ -182,6 +182,8 @@
   "fillincoursename":"请补充填写课程名称",
   "saveCoco":"保存",
   "Donotsave":"不保存",
+  "notsave":"不保存",
+  "wantsavecontent":"是否保存已编辑内容?",
   "Noncannotedit":"非管理员和创建者不可编辑",
   "type":"类型",
   "Searchimagekeywords":"搜索图片关键字",

+ 3 - 2
src/lang/en.json

@@ -167,7 +167,7 @@
   "Joinsuccessfully":"Join successfully",
   "unabletoexit":"Location locked, unable to exit",
   "exist":"exist",
-  "SMARTPaste ":"SMART Paste",
+  "SMARTPaste":"SMART Paste",
   "uploadpictures":"Upload Image",
   "Selectlocalfile":"Select local file",
   "Selectnetworkfiles":"Select network files",
@@ -181,6 +181,7 @@
   "fillincoursename":"Please fill in the course name",
   "wantsavecontent":"Save changes before closing?",
   "saveCoco":"save",
+  "Donotsave":"Do not save",
   "notsave":"Do not save",
   "Noncannotedit":"Non administrators and creators cannot edit",
   "type":"type",
@@ -363,7 +364,7 @@
   "ZoomOut": "Zoom Out",
   "ZoomIn": "Zoom In",
   "ResetL": "Reset",
-  "Rotateleft": "Rotate left 90°",
+  "Rotateleft": "Rotate left 90°",
   "Rotateright": "Rotate right 90°​",
   "Settings": "Settings",
   "QuestionSetup": "Question Setup",

+ 3 - 2
src/lang/hk.json

@@ -168,7 +168,7 @@
   "Joinsuccessfully":"加入成功",
   "unabletoexit":"位置已被鎖定,無法退出",
   "exist":"在",
-  "SMARTPaste ":"智能粘貼",
+  "SMARTPaste":"智能粘貼",
   "uploadpictures":"上傳圖片",
   "Selectlocalfile":"選擇本地文件",
   "Selectnetworkfiles":"選擇網絡文件",
@@ -182,6 +182,7 @@
   "fillincoursename":"請補充填寫課程名稱",
   "wantsavecontent":"是否保存已編輯內容?",
   "saveCoco":"保存",
+  "Donotsave":"不保存",
   "notsave":"不保存",
   "Noncannotedit":"非管理員和創建者不可編輯",
   "type":"類型",
@@ -364,7 +365,7 @@
   "ZoomOut": "縮小",
   "ZoomIn": "放大",
   "ResetL": "復位",
-  "Rotateleft": "左轉90°",
+  "Rotateleft": "左轉90°",
   "Rotateright": "右轉90°",
   "Settings": "排序設置",
   "QuestionSetup": "題目設置",

Some files were not shown because too many files changed in this diff