SanHQin 1 неделя назад
Родитель
Сommit
4945f7cf8e
26 измененных файлов с 294 добавлено и 63 удалено
  1. 1 1
      dist/index.html
  2. 0 0
      dist/static/css/app.f95ce97d394d7420eaf65954a1c2a009.css
  3. 0 0
      dist/static/css/app.f95ce97d394d7420eaf65954a1c2a009.css.map
  4. 0 0
      dist/static/css/workPage.eb039ffafd131baf9f7d229e1701a61b.css
  5. 0 0
      dist/static/css/workPage.eb039ffafd131baf9f7d229e1701a61b.css.map
  6. 0 0
      dist/static/js/app.dcf87be184ffee74a258.js
  7. 0 0
      dist/static/js/app.dcf87be184ffee74a258.js.map
  8. 0 0
      dist/static/js/manifest.23ea04dc469b57e2b4f8.js.map
  9. 0 0
      dist/static/js/workPage-manifest.2ece51fa34be51c8610a.js.map
  10. 0 0
      dist/static/js/workPage-vendor.3c2261c9f54c5ab3df69.js
  11. 0 0
      dist/static/js/workPage-vendor.3c2261c9f54c5ab3df69.js.map
  12. 0 0
      dist/static/js/workPage-vendor.e1fc95e471d70a1519e8.js.map
  13. 0 0
      dist/static/js/workPage.01430ec4079ca7876ac0.js
  14. 0 0
      dist/static/js/workPage.01430ec4079ca7876ac0.js.map
  15. 0 0
      dist/static/js/workPage.46f3ff329154715f71df.js
  16. 0 0
      dist/static/js/workPage.46f3ff329154715f71df.js.map
  17. 1 1
      dist/workPage.html
  18. 52 38
      src/components/pages/pptEasy/addCourse3.vue
  19. 6 6
      src/components/pages/pptEasy/addCoursePS.vue
  20. 8 0
      src/components/pages/workPage/components/photo.vue
  21. 61 4
      src/components/pages/workPage/components/setChoiceQuestion.vue
  22. 56 6
      src/components/pages/workPage/components/setQuestionsAndAnswers.vue
  23. 6 2
      src/lang/cn.json
  24. 6 2
      src/lang/en.json
  25. 6 2
      src/lang/hk.json
  26. 91 1
      src/mixins/mixin.js

+ 1 - 1
dist/index.html

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

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/css/app.f95ce97d394d7420eaf65954a1c2a009.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/css/app.f95ce97d394d7420eaf65954a1c2a009.css.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/css/workPage.eb039ffafd131baf9f7d229e1701a61b.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/css/workPage.eb039ffafd131baf9f7d229e1701a61b.css.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/app.dcf87be184ffee74a258.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/app.dcf87be184ffee74a258.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/manifest.23ea04dc469b57e2b4f8.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/workPage-manifest.2ece51fa34be51c8610a.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/workPage-vendor.3c2261c9f54c5ab3df69.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/workPage-vendor.3c2261c9f54c5ab3df69.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/workPage-vendor.e1fc95e471d70a1519e8.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/workPage.01430ec4079ca7876ac0.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/workPage.01430ec4079ca7876ac0.js.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/workPage.46f3ff329154715f71df.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/static/js/workPage.46f3ff329154715f71df.js.map


+ 1 - 1
dist/workPage.html

@@ -1,4 +1,4 @@
-<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>工作页面 - CocoFlow</title><link rel=icon href=../static/logo.ico><link href=./static/css/workPage.dceabcb058ed06914fde43af1b3e6067.css rel=stylesheet></head><body><noscript><strong>We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script type=text/javascript src=./static/js/workPage-manifest.2ece51fa34be51c8610a.js></script><script type=text/javascript src=./static/js/workPage-vendor.e1fc95e471d70a1519e8.js></script><script type=text/javascript src=./static/js/workPage.46f3ff329154715f71df.js></script></body></html><script>function stopSafari() {
+<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>工作页面 - CocoFlow</title><link rel=icon href=../static/logo.ico><link href=./static/css/workPage.eb039ffafd131baf9f7d229e1701a61b.css rel=stylesheet></head><body><noscript><strong>We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script type=text/javascript src=./static/js/workPage-manifest.2ece51fa34be51c8610a.js></script><script type=text/javascript src=./static/js/workPage-vendor.3c2261c9f54c5ab3df69.js></script><script type=text/javascript src=./static/js/workPage.01430ec4079ca7876ac0.js></script></body></html><script>function stopSafari() {
     //阻止safari浏览器双击放大功能
     let lastTouchEnd = 0  //更新手指弹起的时间
     document.documentElement.addEventListener("touchstart", function (event) {

+ 52 - 38
src/components/pages/pptEasy/addCourse3.vue

@@ -868,7 +868,13 @@
               <div class="form-row">
                 <div class="form-item aiAssistant-item">
                   <div class="aiAssistant_box">
-                      <label class="aiAssistant_box_title">{{ lang.ssAIAssistant }}</label>
+                      <label class="aiAssistant_box_title">
+                        {{ lang.ssAIAssistant }}
+                        <el-tooltip :content="lang.ssAIAssistantTip" placement="top" effect="dark">
+                          <!-- content to trigger tooltip here -->
+                           <svg t="1785306438724" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6639" width="128" height="128"><path d="M512 993.882353C245.850353 993.882353 30.117647 778.149647 30.117647 512S245.850353 30.117647 512 30.117647s481.882353 215.732706 481.882353 481.882353-215.732706 481.882353-481.882353 481.882353z m0-60.235294c232.869647 0 421.647059-188.777412 421.647059-421.647059S744.869647 90.352941 512 90.352941 90.352941 279.130353 90.352941 512s188.777412 421.647059 421.647059 421.647059z" fill="#bfbfbf" p-id="6640"></path><path d="M459.956706 763.572706c-5.12-34.665412-1.204706-105.893647 0-120.530824l5.300706-165.49647c0.963765-15.36-7.981176-11.444706-14.125177-8.553412-29.816471 14.215529-64.602353 40.357647-64.602353 40.357647s21.172706-57.283765 41.592471-81.227294c15.088941-21.052235 47.465412-49.182118 71.258353-51.410824 28.039529 0.602353 42.405647 4.848941 40.05647 74.842353 0 0-4.698353 215.100235-0.662588 252.596706 4.096 11.956706 43.339294-15.209412 48.850824-19.516235 5.541647-4.306824 56.32-50.176 56.32-50.176S602.352941 759.868235 522.300235 787.787294c-28.521412 9.938824-58.066824 5.150118-62.373647-24.214588z" fill="#bfbfbf" opacity=".99" p-id="6641"></path><path d="M503.717647 285.364706m-52.495059 0a52.495059 52.495059 0 1 0 104.990118 0 52.495059 52.495059 0 1 0-104.990118 0Z" fill="#bfbfbf" p-id="6642"></path><path d="M0 0h1024v1024H0z" fill="#bfbfbf" fill-opacity="0" p-id="6643"></path></svg>
+                        </el-tooltip>
+                      </label>
                       <div class="ai-switch-wrapper">
                         <el-switch v-model="aiAssistant" active-color="#FF8C00" inactive-color="#DCDFE6"></el-switch>
                       </div>
@@ -1347,7 +1353,27 @@ export default {
       }
     },
     // 打开发布弹窗
-    openPublishDialog() {
+    async openPublishDialog() {
+      if (this.$refs.pptIframeRef.contentWindow.window.pptLoading !== 2) return this.$message.info(this.lang.ssPptLoad)
+      let _pptData = await this.getPPtJson();
+      const _pptData2 = JSON.parse(JSON.stringify(_pptData))
+      let toolsArrayCont = []
+      let istoolsArray = false
+      if (_pptData2.slides) {
+        toolsArrayCont = _pptData2.slides.some(slide => slide.toolsArray && slide.toolsArray.length > 0)
+        if (toolsArrayCont) {
+          // 有内容就弹出弹窗
+          istoolsArray = true
+        }
+      }
+
+      if(istoolsArray){
+        const confirmed = await this.showToolsConfirmDialog();
+        if (!confirmed) {
+          this.uploadWorkLoading = false;
+          return;
+        }
+      }
       this.initCourseSettingsOptions();
       this.loadClassOptions();
       this.dialogVisiblePublish = true;
@@ -1387,16 +1413,16 @@ export default {
     },
     // 确认发布
     confirmPublish() {
-      if (!this.selectedSubject) {
-        this.$message.error('请选择学科');
+      if (!this.selectedSubject.length) {
+        this.$message.error(this.lang.ssSelectSubject);
         return;
       }
-      if (!this.selectGrage) {
-        this.$message.error('请选择年级');
+      if (!this.selectedGrade.length) {
+        this.$message.error(this.lang.ssSelectGrade);
         return;
       }
-      if (!this.checkboxList2) {
-        this.$message.error('请选择班级');
+      if (!this.checkboxList2.length) {
+        this.$message.error(this.lang.ssSelectClass2);
         return;
       }
 
@@ -1404,7 +1430,7 @@ export default {
       // 模拟发布过程
       console.log('发布课程:', {
         subject: this.selectedSubject,
-        grade: this.selectGrage,
+        grade: this.selectedGrade,
         class: this.checkboxList2,
         visibility: this.isTeacherSee,
         aiAssistant: this.aiAssistant
@@ -1950,8 +1976,6 @@ export default {
       }
       const _pptData2 = JSON.parse(JSON.stringify(_pptData))
       const pptContent = []
-      let toolsArrayCont = []
-      let istoolsArray = false
       if (_pptData2.slides) {
         _pptData2.slides.forEach((slide, index) => {
           let slideContent = ''
@@ -1966,20 +1990,8 @@ export default {
           }
           pptContent.push(`第${index + 1}页: ${slideContent || '内容为空'}`)
         })
-        toolsArrayCont = _pptData2.slides.some(slide => slide.toolsArray && slide.toolsArray.length > 0)
-        if (toolsArrayCont) {
-          // 有内容就弹出弹窗
-          istoolsArray = true
-        }
       }
 
-      if(istoolsArray && type == 1){
-        const confirmed = await this.showToolsConfirmDialog();
-        if (!confirmed) {
-          this.uploadWorkLoading = false;
-          return;
-        }
-      }
       const contentDescription = pptContent.join('\n')
       // 用_pptData生成json文件,并生成File对象
       const pptJsonStr = JSON.stringify(_pptData, null, 2);
@@ -2085,8 +2097,6 @@ export default {
       }
       const _pptData2 = JSON.parse(JSON.stringify(_pptData))
       const pptContent = []
-      let toolsArrayCont = []
-      let istoolsArray = false
       if (_pptData2.slides) {
         _pptData2.slides.forEach((slide, index) => {
           let slideContent = ''
@@ -2101,19 +2111,8 @@ export default {
           }
           pptContent.push(`第${index + 1}页: ${slideContent || '内容为空'}`)
         })
-        toolsArrayCont = _pptData2.slides.some(slide => slide.toolsArray && slide.toolsArray.length > 0)
-        if (toolsArrayCont) {
-          // 有内容就弹出弹窗
-          istoolsArray = true
-        }
-      }
-      if(istoolsArray && type == 1){
-        const confirmed = await this.showToolsConfirmDialog();
-        if (!confirmed) {
-          this.uploadWorkLoading = false;
-          return;
-        }
       }
+
       const contentDescription = pptContent.join('\n')
       // 用_pptData生成json文件,并生成File对象
       const pptJsonStr = JSON.stringify(_pptData, null, 2);
@@ -3715,6 +3714,11 @@ export default {
       // this.dialogVisibleBasicInfo = true
       this.openPublishDialog()
     }
+    window.publishCourse2 = () => {
+      this.initCourseSettingsOptions();
+      this.loadClassOptions();
+      this.dialogVisiblePublish = true;
+    }
     window.openCourseSettings = () => this.openCourseSettings();
   }
 };
@@ -5664,7 +5668,17 @@ export default {
   box-sizing: border-box;
 }
 
-.aiAssistant_box_title{}
+.aiAssistant_box_title{
+  display: flex;
+  align-items: center;
+}
+
+.aiAssistant_box_title svg{
+  margin-left: 8px;
+  width: 16px;
+  height: 16px;
+  cursor: pointer;
+}
 
 .ai-switch-wrapper{}
 </style>

+ 6 - 6
src/components/pages/pptEasy/addCoursePS.vue

@@ -1387,16 +1387,16 @@ export default {
     },
     // 确认发布
     confirmPublish() {
-      if (!this.selectedSubject) {
-        this.$message.error('请选择学科');
+      if (!this.selectedSubject.length) {
+        this.$message.error(this.lang.ssSelectSubject);
         return;
       }
-      if (!this.selectGrage) {
-        this.$message.error('请选择年级');
+      if (!this.selectedGrade.length) {
+        this.$message.error(this.lang.ssSelectGrade);
         return;
       }
-      if (!this.checkboxList2) {
-        this.$message.error('请选择班级');
+      if (!this.checkboxList2.length) {
+        this.$message.error(this.lang.ssSelectClass2);
         return;
       }
 

+ 8 - 0
src/components/pages/workPage/components/photo.vue

@@ -108,6 +108,14 @@ export default {
       input.onchange = (e) => {
         const files = e.target.files;
         if (files && files.length > 0) {
+          // 限制文件大小不超过20MB
+          const maxSize = 20 * 1024 * 1024; // 20MB
+          for (let i = 0; i < files.length; i++) {
+            if (files[i].size > maxSize) {
+              this.$message.error(lang.ssFileTooBig);
+              return;
+            }
+          }
           this.uploadLoading = true;
           const uploadPromises = [];
           for (let i = 0; i < files.length; i++) {

+ 61 - 4
src/components/pages/workPage/components/setChoiceQuestion.vue

@@ -136,17 +136,17 @@
       <div class="explanation">
         <div class="e_header">
           <span>{{ lang.ssExplanationTip }}</span>
-          <div v-show="false">
+          <div @click="generateExplanation(item, index)" :disabled="chatLoading[index]" v-loading="messagesloading[index]">
             <svg t="1774233113566" viewBox="0 0 1027 1024" width="200" height="200">
               <path
-                d="M511.979521 544.586217a54.525819 54.525819 0 0 1-23.359066-5.247791L31.038758 321.427143a54.397824 54.397824 0 0 1 0-98.236071L488.620455 5.279789c14.719411-7.039718 31.99872-7.039718 46.718131 0l457.581697 217.911283a54.397824 54.397824 0 0 1 0 98.236071l-457.581697 217.911283A54.525819 54.525819 0 0 1 511.979521 544.586217zM180.984761 272.341106L511.979521 429.966801l331.058757-157.625695L511.979521 114.587417 180.984761 272.341106z m354.417823 746.402144l457.517699-217.911283a54.397824 54.397824 0 1 0-46.718131-98.236071L511.979521 909.371625l-434.158634-206.775729a54.397824 54.397824 0 0 0-46.718131 98.236071l457.581697 217.911283a54.525819 54.525819 0 0 0 46.718131 0z m0-239.73441l457.517699-217.847286a54.397824 54.397824 0 1 0-46.718131-98.300068L511.979521 669.573217l-434.158634-206.711731a54.397824 54.397824 0 0 0-46.718131 98.300068l457.581697 217.847286a54.525819 54.525819 0 0 0 46.718131 0z"
+                d="M511.979521 544.586217a54.525819 54.525819 0 0 1-23.359066-5.247791L31.038758 321.427143a54.397824 54.397824 0 0 1 0-98.236071L488.620455 5.279789c14.719411-7.039718 31.99872-7.039718 46.718131 0l457.581697 217.911283a54.397824 54.397824 0 0 1 0 98.236071l-457.581697 217.911283A54.525819 54.525819 0 0 1 511.979521 544.586217zM180.984761 272.341106L511.979521 429.966801l331.058757-157.625695L511.979521 114.587417 180.984761 272.341106z m354.417823 746.402144l457.517699-217.911283a54.397824 54.397824 0 1 0-46.718131-98.236071L511.979521 909.371625l-434.158634-206.775729a54.397824 54.397824 0 0 0-46.718131 98.300068l457.581697 217.847286a54.525819 54.525819 0 0 0 46.718131 0z m0-239.73441l457.517699-217.847286a54.397824 54.397824 0 1 0-46.718131-98.300068L511.979521 669.573217l-434.158634-206.711731a54.397824 54.397824 0 0 0-46.718131 98.300068l457.581697 217.847286a54.525819 54.525819 0 0 0 46.718131 0z"
                 p-id="9073"></path>
             </svg>
-            <span>{{ lang.ssAIGenerate }}</span>
+            <span>{{ chatLoading[index] ? lang.ssGenerating : lang.ssAIGenerate }}</span>
           </div>
         </div>
         <el-input type="textarea" rows="3" style="font-size: 1.2rem;" resize="none" v-model="item.explanation"
-          :placeholder="lang.ssEnterExplanation" @input="setTestJson()"></el-input>
+          :placeholder="lang.ssEnterExplanation" v-loading="messagesloading[index]" :disabled="chatLoading[index]" @input="setTestJson()"></el-input>
       </div>
     </div>
 
@@ -167,7 +167,10 @@
 <script>
 import { v4 as uuidv4 } from 'uuid';
 import { uploadOneFile } from '@/components/tools/uploadFile'
+import { myMixin } from '@/mixins/mixin'
+
 export default {
+  mixins: [myMixin],
   emits: ['setTestJson', 'save'],
   props: {
     workData: {
@@ -180,6 +183,10 @@ export default {
       jsonData: {},
       dragItem: null,
       delJson:null,
+      streamController: [],
+      chatLoading: [],
+      messagesloading: [],
+      userid: this.$route.query.userid,
     }
   },
   watch: {
@@ -427,6 +434,56 @@ export default {
         this.delJson = null;
       }
     },
+    // 生成解释
+    async generateExplanation(item, index) {
+      if (this.chatLoading[index]) {
+        this.$message.warning(this.lang.ssPleaseWait);
+        return
+      }
+      if (this.messagesloading[index]) {
+        this.$message.warning(this.lang.ssPleaseWait);
+        return
+      }
+      let zimu = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+      let prompt = `- 题干:${item.teststitle}
+      - 选项:  
+        ${item.checkList.map((check, index) => `${zimu[index]}. ${check}`).join('\n')}
+      - 正确答案(若已知):${item.answer.length > 0 ? item.answer.map(index => zimu[index]).join('、') : '未知'}`
+      this.chatLoading[index] = true
+      this.messagesloading[index] = true
+      this.$forceUpdate()
+      this.chat_stream(prompt, '7dc8f9f4-415e-4cc6-a572-68bd758e9c8b', this.userid || this.workData.userid, this.lang.lang, (event) => {
+        if (event.type === 'message') {
+          this.jsonData.testJson[index].explanation = event.data
+          this.messagesloading[index] = false
+        }
+        else if (event.type === 'messageEnd') {
+          this.jsonData.testJson[index].explanation = event.data
+          this.messagesloading[index] = false
+          this.chatLoading[index] = false
+          this.$forceUpdate()
+        }else if (event.type === 'error') {
+          this.chatLoading[index] = false
+          this.messagesloading[index] = false
+          this.$message.error(event.data)
+        }
+      }).then(controller => {
+        this.streamController[index] = controller
+      }).catch(err => {
+        this.chatLoading[index] = false
+        this.messagesloading[index] = false
+        console.log('err', err)
+        this.stopMessage(index)
+      })
+    },
+    stopMessage(index) {
+      if (this.streamController[index]) {
+        this.streamController[index].abort()
+        this.streamController[index] = null
+      }
+      this.chatLoading[index] = false
+      this.messagesloading[index] = false
+    }
   },
   mounted() {
     window.addEventListener('keydown', (e)=>{

+ 56 - 6
src/components/pages/workPage/components/setQuestionsAndAnswers.vue

@@ -61,17 +61,17 @@
       <div class="explanation">
         <div class="e_header">
           <span>{{ lang.ssEvaluationStandard }}</span>
-          <!-- <div v-show="false">
+          <div @click="generateExplanation()" :disabled="chatLoading" v-loading="messagesloading">
             <svg t="1774233113566" viewBox="0 0 1027 1024" width="200" height="200">
               <path
-                d="M511.979521 544.586217a54.525819 54.525819 0 0 1-23.359066-5.247791L31.038758 321.427143a54.397824 54.397824 0 0 1 0-98.236071L488.620455 5.279789c14.719411-7.039718 31.99872-7.039718 46.718131 0l457.581697 217.911283a54.397824 54.397824 0 0 1 0 98.236071l-457.581697 217.911283A54.525819 54.525819 0 0 1 511.979521 544.586217zM180.984761 272.341106L511.979521 429.966801l331.058757-157.625695L511.979521 114.587417 180.984761 272.341106z m354.417823 746.402144l457.517699-217.911283a54.397824 54.397824 0 1 0-46.718131-98.236071L511.979521 909.371625l-434.158634-206.775729a54.397824 54.397824 0 0 0-46.718131 98.236071l457.581697 217.911283a54.525819 54.525819 0 0 0 46.718131 0z m0-239.73441l457.517699-217.847286a54.397824 54.397824 0 1 0-46.718131-98.300068L511.979521 669.573217l-434.158634-206.711731a54.397824 54.397824 0 0 0-46.718131 98.300068l457.581697 217.847286a54.525819 54.525819 0 0 0 46.718131 0z"
+                d="M511.979521 544.586217a54.525819 54.525819 0 0 1-23.359066-5.247791L31.038758 321.427143a54.397824 54.397824 0 0 1 0-98.236071L488.620455 5.279789c14.719411-7.039718 31.99872-7.039718 46.718131 0l457.581697 217.911283a54.397824 54.397824 0 0 1 0 98.236071l-457.581697 217.911283A54.525819 54.525819 0 0 1 511.979521 544.586217zM180.984761 272.341106L511.979521 429.966801l331.058757-157.625695L511.979521 114.587417 180.984761 272.341106z m354.417823 746.402144l457.517699-217.911283a54.397824 54.397824 0 1 0-46.718131-98.236071L511.979521 909.371625l-434.158634-206.775729a54.397824 54.397824 0 0 0-46.718131 98.300068l457.581697 217.847286a54.525819 54.525819 0 0 0 46.718131 0z m0-239.73441l457.517699-217.847286a54.397824 54.397824 0 1 0-46.718131-98.300068L511.979521 669.573217l-434.158634-206.711731a54.397824 54.397824 0 0 0-46.718131 98.300068l457.581697 217.847286a54.525819 54.525819 0 0 0 46.718131 0z"
                 p-id="9073"></path>
             </svg>
-            <span>AI生成</span>
-          </div> -->
+            <span>{{ chatLoading ? lang.ssGenerating : lang.ssAIGenerate }}</span>
+          </div>
         </div>
         <el-input type="textarea" rows="3" resize="none" v-model="jsonData.evaluationCriteria" :placeholder="lang.ssEnterEvaluationStandard"
-          @input="setTestJson()"></el-input>
+          @input="setTestJson()" v-loading="messagesloading" :disabled="chatLoading"></el-input>
       </div>
     </div>
 
@@ -80,7 +80,9 @@
 
 <script>
 import { uploadOneFile } from '@/components/tools/uploadFile'
+import { myMixin } from '@/mixins/mixin'
 export default {
+  mixins: [myMixin],
   emits: ['setTestJson', 'save'],
   props: {
     workData: {
@@ -90,7 +92,11 @@ export default {
   },
   data() {
     return {
-      jsonData: {}
+      jsonData: {},
+      streamController: [],
+      chatLoading: false,
+      messagesloading: false,
+      userid: this.$route.query.userid,
     }
   },
   watch: {
@@ -158,6 +164,50 @@ export default {
       // }
       this.setTestJson();
     },
+    // 生成解释
+    async generateExplanation() {
+      if (this.chatLoading) {
+        this.$message.warning(this.lang.ssPleaseWait);
+        return
+      }
+      if (this.messagesloading) {
+        this.$message.warning(this.lang.ssPleaseWait);
+        return
+      }
+      let prompt = `- 题干:${this.jsonData.answerQ}`
+      this.chatLoading = true
+      this.messagesloading = true
+      this.chat_stream(prompt, '5edc10d5-8635-4fe6-9670-8b2d9e8005aa', this.userid || this.workData.userid, this.lang.lang, (event) => {
+        if (event.type === 'message') {
+          this.jsonData.evaluationCriteria = event.data
+          this.messagesloading = false
+        }
+        else if (event.type === 'messageEnd') {
+          this.jsonData.evaluationCriteria = event.data
+          this.messagesloading = false
+          this.chatLoading = false
+        }else if (event.type === 'error') {
+          this.chatLoading = false
+          this.messagesloading = false
+          this.$message.error(event.data)
+        }
+      }).then(controller => {
+        this.streamController = controller
+      }).catch(err => {
+        this.chatLoading = false
+        this.messagesloading = false
+        console.log('err', err)
+        this.stopMessage()
+      })
+    },
+    stopMessage() {
+      if (this.streamController) {
+        this.streamController.abort()
+        this.streamController = null
+      }
+      this.chatLoading = false
+      this.messagesloading = false
+    }
   },
 }
 </script>

+ 6 - 2
src/lang/cn.json

@@ -2047,6 +2047,7 @@
   "ssConfirmDeleteClassStudentone":"确认移除*学生?",
   "ssExplanationTip":"解释说明",
   "ssAIGenerate":"AI生成",
+  "ssGenerating":"生成中...",
   "ssEnterExplanation":"请输入解释说明",
   "ssEvaluationStandard":"评价标准",
   "ssEnterEvaluationStandard":"请输入评价标准",
@@ -2060,7 +2061,10 @@
   "allGrades": "全部年级",
   "ssVoteTopic": "投票主题",
   "ssUnconfirmedToolPage": "存在未确认的工具页",
-  "ssUnconfirmedToolPageTip": "存在未确认的工具页,请完成后发布课程。",
+  "ssUnconfirmedToolPageTip": "存在未确认的工具页,请完成后发布课程(学生端不会显示工具页面)。",
   "ssIgnoreAndPublish": "忽略并发布",
-  "ssReturnModify": "返回修改"
+  "ssReturnModify": "返回修改",
+  "ssPleaseWait": "请稍后再试",
+  "ssFileTooBig":"上传文件大小不能超过20MB, 请重新上传",
+  "ssAIAssistantTip":"开启后学生在提交完作业后,会弹出AI助手,帮助学生查看提交作业结果"
 }

+ 6 - 2
src/lang/en.json

@@ -2046,6 +2046,7 @@
   "ssConfirmDeleteClassStudentone":"Confirm remove * student?",
   "ssExplanationTip":"Explanation",
   "ssAIGenerate":"AI Generate",
+  "ssGenerating":"Generating...",
   "ssEnterExplanation":"Please enter explanation",
   "ssEvaluationStandard":"Evaluation Standard",
   "ssEnterEvaluationStandard":"Please enter evaluation standard",
@@ -2059,7 +2060,10 @@
   "allGrades": "All Grades",
   "ssVoteTopic": "Voting Theme",
   "ssUnconfirmedToolPage": "Unconfirmed Tool Page",
-  "ssUnconfirmedToolPageTip": "Unconfirmed tool page, please publish the course after completion.",
+  "ssUnconfirmedToolPageTip": "Unconfirmed tool page, please publish the course after completion (student end will not display the tool page).",
   "ssIgnoreAndPublish": "Ignore and publish",
-  "ssReturnModify": "Return to modify"
+  "ssReturnModify": "Return to modify",
+  "ssPleaseWait": "Please wait, try again later.",
+  "ssFileTooBig":"The uploaded file size cannot exceed 20MB, please re-upload.",
+  "ssAIAssistantTip":"After enabling, students will be able to view the results of their submitted assignments in the AI assistant after submitting them."
 }

+ 6 - 2
src/lang/hk.json

@@ -2046,6 +2046,7 @@
   "ssConfirmDeleteClassStudentone":"確定移除 * 名學生嗎?",
   "ssExplanationTip":"解釋說明",
   "ssAIGenerate":"AI生成",
+  "ssGenerating":"生成中...",
   "ssEnterExplanation":"請輸入解釋說明",
   "ssEvaluationStandard":"評價標準",
   "ssEnterEvaluationStandard":"請輸入評價標準",
@@ -2060,7 +2061,10 @@
   "allGrades": "全部年級",
   "ssVoteTopic": "投票主題",
   "ssUnconfirmedToolPage": "存在未確認的工具頁", 
-  "ssUnconfirmedToolPageTip": "存在未確認的工具頁,請完成後發布課程。",
+  "ssUnconfirmedToolPageTip": "存在未確認的工具頁,請完成後發布課程(學生端不會顯示工具頁面)。",
   "ssIgnoreAndPublish": "忽略並發布",
-  "ssReturnModify": "返回修改"
+  "ssReturnModify": "返回修改",
+  "ssPleaseWait": "請稍後再試",
+  "ssFileTooBig":"上傳文件大小不能超過20MB, 請重新上傳",
+  "ssAIAssistantTip":"開啟後學生在提交完作後,會彈出AI助手,幫助學生查看提交作業結果。"
 }

+ 91 - 1
src/mixins/mixin.js

@@ -1,10 +1,13 @@
 import { v4 as uuidv4 } from "uuid";
+import { fetchEventSource } from "@microsoft/fetch-event-source";
+
 
 export const myMixin = {
   data() {
     return {
         userJson: {},
-        new_url: 'https://appapi.cocorobo.cn'
+        new_url: 'https://appapi.cocorobo.cn',
+        model: {}
     };
   },
   methods: {
@@ -134,5 +137,92 @@ export const myMixin = {
           });
       })
     },
+    async getAgentModel(agentId) {
+      if (this.model[agentId]) {
+        return this.model[agentId]
+      }
+      const res = await this.ajax.get('https://appapi.cocorobo.cn/api/agents/agent/' + agentId)
+      this.model[agentId] = res
+      return this.model[agentId]
+    },
+    getTtsLanguage(language) {
+      if (language === 'com') {
+        return 'en-US'
+      } else if (language === 'hk') {
+        return 'zh-HK'
+      } else {
+        return 'zh-CN'
+      }
+    },
+    chat_stream(msg, agentId, userId, language, onMessage, session_name, file_ids, modelName) {
+      const self = this
+      return new Promise(function(resolve) {
+        self.getAgentModel(agentId).then(function(agentData) {
+          var params = {
+            id: agentId,
+            file_ids: file_ids || [],
+            message: 'Language: ' + (language === 'com' ? 'English' : (language === 'hk' ? 'Traditional Chinese' : 'Chinese')) + ' ' + msg + '  ' + (language === 'hk' ? '請用繁體中文回复' : (language === 'com' ? 'Please reply in English' : '请用中文回复')),
+            uid: uuidv4(),
+            stream: true,
+            model: modelName || (agentData && agentData.modelType) || 'open-doubao',
+            userId: userId,
+            tts_language: self.getTtsLanguage(language),
+            session_name: session_name || uuidv4()
+          }
+
+          var ctrl = new AbortController()
+          var content = ''
+          
+          fetchEventSource('https://appapi.cocorobo.cn/api/agentchats/ai_agent_chat', {
+            method: 'POST',
+            body: JSON.stringify(params),
+            signal: ctrl.signal,
+            headers: {
+              'Content-Type': 'application/json',
+            },
+            onmessage: function(event) {
+              var data = JSON.parse(event.data)
+              if (data.content) {
+                if (data.content != '[DONE]') {
+                  content += data.content
+                  onMessage({
+                    type: 'message',
+                    data: content
+                  })
+                } else {
+                  onMessage({
+                    type: 'messageEnd',
+                    data: content
+                  })
+                }
+              }
+            },
+            onclose: function() {
+              onMessage({
+                type: 'close',
+                data: 'SSE Connection closed'
+              })
+            },
+            onerror: function(err) {
+              onMessage({
+                type: 'error',
+                data: err.message || 'Unknown error'
+              })
+              throw err
+            },
+          }).catch(function(err) {
+            onMessage({
+              type: 'error',
+              data: err || 'Unknown error'
+            })
+            console.log('err', err)
+          })
+          
+          resolve({
+            abort: function() { ctrl.abort() }
+          })
+        })
+      })
+    }
   }
 };

Некоторые файлы не были показаны из-за большого количества измененных файлов