소스 검색

1、blockly新页面—— AI图片视频、音乐功能

liyanbo 6 달 전
부모
커밋
9a34be86ce
1개의 변경된 파일191개의 추가작업 그리고 64개의 파일을 삭제
  1. 191 64
      src/components/blockly/BlocklyEditor.vue

+ 191 - 64
src/components/blockly/BlocklyEditor.vue

@@ -37,6 +37,7 @@
       </div>
     </div>
 
+<!--    工具箱-->
     <div class="content">
       <div class="toolbox-section">
         <h2>工具箱</h2>
@@ -97,8 +98,34 @@
           </div>
         </div>
 
+        <!-- 在template部分的适当位置音频播放器组件 -->
+        <div class="music-player-container" v-if="state.currentMusicUrl">
+          <h5>音乐播放</h5>
+          <audio
+              ref="musicPlayer"
+              :src="state.currentMusicUrl"
+              @ended="handleMusicEnded"
+              preload="metadata">
+            您的浏览器不支持音频元素
+          </audio>
+          <div class="music-status">
+            <p v-if="state.isMusicPlaying">正在播放: {{ state.currentMusicName }}</p>
+            <p v-else>准备就绪</p>
+          </div>
+          <!-- 停止播放按钮 - 修复点击事件 -->
+          <el-button
+              v-if="state.isMusicPlaying"
+              type="danger"
+              size="small"
+              @click="handleStopMusic"
+              style="margin-top: 10px;">
+            停止播放
+          </el-button>
+        </div>
+
       </div>
 
+<!--      工作区-->
       <div class="workspace-section">
         <h2>工作区</h2>
         <div id="blocklyDiv"></div>
@@ -109,6 +136,7 @@
         </div>
       </div>
 
+<!--      输出-->
       <div class="output-section">
         <h2>输出</h2>
         <div class="controls">
@@ -116,6 +144,23 @@
         </div>
         <pre id="output">{{ output }}</pre>
       </div>
+
+
+      <!-- AI结果预览模态框 -->
+      <div v-if="state.previewVisible" class="preview-modal" @click="handleClosePreview">
+        <div class="preview-content" @click.stop>
+          <button class="close-button" @click="handleClosePreview">&times;</button>
+          <div v-if="state.previewType === 'image'" class="preview-image-container">
+            <img :src="state.previewContent" alt="AI生成图片" class="preview-image">
+          </div>
+          <div v-else-if="state.previewType === 'video'" class="preview-video-container">
+            <video :src="state.previewContent" controls class="preview-video"></video>
+          </div>
+          <div v-else-if="state.previewType === 'text'" class="preview-text-container">
+            {{ state.previewContent }}
+          </div>
+        </div>
+      </div>
     </div>
   </div>
 </template>
@@ -144,6 +189,7 @@ import { ModelTypeEnum } from "@/api/teachers.js";
 import { globalState } from "@/utils/globalState.js";
 //音乐
 import { playMusic, stopMusic, onMusicEnded } from "@/api/blockly/music.js";
+import {ElButton} from "element-plus";
 
 const router = useRouter();
 // 台灯预览显示状态
@@ -172,60 +218,90 @@ const jsonData = ref(`{
     "languageVersion": 0,
     "blocks": [
       {
-        "type": "text_print",
-        "x": 100,
-        "y": 100,
-        "inputs": {
-          "TEXT": {
-            "block": {
-              "type": "text",
-              "fields": {
-                "TEXT": "Hello, Blockly!"
-              }
-            }
+        "type": "variables_set",
+        "id": "kM:Fgf:wd4U3Z$j0x8oK",
+        "x": 90,
+        "y": 130,
+        "fields": {
+          "VAR": {
+            "id": "MHW(ZbOKhL!/An\`5N@6\`"
           }
-        }
-      },
-      {
-        "type": "controls_if",
-        "x": 100,
-        "y": 200,
+        },
         "inputs": {
-          "IF0": {
+          "VALUE": {
             "block": {
-              "type": "logic_compare",
+              "type": "ai_voice_input",
+              "id": "l5E=g|1L+4hThQ8v})lQ",
               "fields": {
-                "OP": "EQ"
+                "LANGUAGE": "zh-CN"
               },
               "inputs": {
-                "A": {
+                "PROMPT": {
                   "block": {
-                    "type": "math_number",
+                    "type": "text",
+                    "id": "Q*n.c_)@7j^E2=s5/X!n",
                     "fields": {
-                      "NUM": 5
+                      "TEXT": "请发言:"
                     }
                   }
-                },
-                "B": {
-                  "block": {
-                    "type": "math_number",
-                    "fields": {
-                      "NUM": 5
+                }
+              }
+            }
+          }
+        },
+        "next": {
+          "block": {
+            "type": "variables_set",
+            "id": "]g.xbBe.i=a9B*Kfw@|\`",
+            "fields": {
+              "VAR": {
+                "id": "zn.7{ZqbUaH1?P,R05hF"
+              }
+            },
+            "inputs": {
+              "VALUE": {
+                "block": {
+                  "type": "ai_text_to_text",
+                  "id": "R$h+R!6#@+4=+WX1*nvh",
+                  "inputs": {
+                    "PROMPT": {
+                      "block": {
+                        "type": "variables_get",
+                        "id": "h$S$nt)3VU.=nX*W-mo~",
+                        "fields": {
+                          "VAR": {
+                            "id": "MHW(ZbOKhL!/An\`5N@6\`"
+                          }
+                        }
+                      }
+                    },
+                    "提示词": {
+                      "block": {
+                        "type": "text",
+                        "id": "7k%sgLP?i]e[,m^49P++",
+                        "fields": {
+                          "TEXT": "请只回复我指定格式:白,100,热闹"
+                        }
+                      }
                     }
                   }
                 }
               }
-            }
-          },
-          "DO0": {
-            "block": {
-              "type": "text_print",
-              "inputs": {
-                "TEXT": {
-                  "block": {
-                    "type": "text",
-                    "fields": {
-                      "TEXT": "条件成立!"
+            },
+            "next": {
+              "block": {
+                "type": "ai_smart_lamp_single_param",
+                "id": "!.0;Ktwm+Z?o8_9FRa}G",
+                "inputs": {
+                  "PARAMS": {
+                    "block": {
+                      "type": "variables_get",
+                      "id": "d{cIJ-kEFFQcn~%A,g@g",
+                      "fields": {
+                        "VAR": {
+                          "id": "zn.7{ZqbUaH1?P,R05hF"
+                        }
+                      }
                     }
                   }
                 }
@@ -235,7 +311,17 @@ const jsonData = ref(`{
         }
       }
     ]
-  }
+  },
+  "variables": [
+    {
+      "name": "inputText",
+      "id": "MHW(ZbOKhL!/An\`5N@6\`"
+    },
+    {
+      "name": "lampConfig",
+      "id": "zn.7{ZqbUaH1?P,R05hF"
+    }
+  ]
 }`);
 
 const output = ref('// 生成的代码将显示在这里\n');
@@ -603,9 +689,6 @@ const aiService = {
                 state.generatedContent.text = resultText;
                 state.previewType = "text";
                 state.previewContent = resultText;
-                if (!state.previewVisible) {
-                  state.previewVisible = true;
-                }
               } else {
                 // 更新预览内容
                 state.generatedContent.text = resultText;
@@ -633,9 +716,6 @@ const aiService = {
       state.generatedContent.text = resultText;
       state.previewType = "text";
       state.previewContent = resultText;
-      if (!state.previewVisible) {
-        state.previewVisible = true;
-      }
     }
 
     return resultText;
@@ -1259,6 +1339,7 @@ const generateCode = (language = 'javascript') => {
 const runCode = async () => {
   try {
     const code = javascriptGenerator.workspaceToCode(workspace);
+    // 初始化输出区域,显示生成的代码和执行结果标题
     output.value = code + '\n\n// 执行结果:\n';
 
     // 保存原始console方法
@@ -1269,30 +1350,72 @@ const runCode = async () => {
     // 创建输出缓冲区
     let outputBuffer = "";
 
-    // 重定义console方法
+    // 重定义console.log方法,确保所有日志都输出到output变量
     console.log = (...args) => {
-      const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : arg).join(' ');
-      outputBuffer += message + '\n';
-      output.value = code + '\n\n// 执行结果:\n' + outputBuffer;
+      // 将参数转换为字符串
+      const message = args.map(arg => {
+        if (typeof arg === 'object') {
+          try {
+            return JSON.stringify(arg, null, 2);
+          } catch (e) {
+            return String(arg);
+          }
+        }
+        return arg;
+      }).join(' ');
+
+      // 过滤掉Vue警告信息
+      if (!message.includes('[Vue warn]')) {
+        outputBuffer += message + '\n';
+        // 实时更新输出区域内容
+        output.value = code + '\n\n// 执行结果:\n' + outputBuffer;
+      }
+      // 保留原始console.log功能
       originalConsoleLog.apply(console, args);
     };
 
+    // 重定义console.error方法
     console.error = (...args) => {
-      const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : arg).join(' ');
-      outputBuffer += '// 错误: ' + message + '\n';
-      output.value = code + '\n\n// 执行结果:\n' + outputBuffer;
+      const message = args.map(arg => {
+        if (typeof arg === 'object') {
+          try {
+            return JSON.stringify(arg, null, 2);
+          } catch (e) {
+            return String(arg);
+          }
+        }
+        return arg;
+      }).join(' ');
+
+      if (!message.includes('[Vue warn]')) {
+        outputBuffer += '// 错误: ' + message + '\n';
+        output.value = code + '\n\n// 执行结果:\n' + outputBuffer;
+      }
       originalConsoleError.apply(console, args);
     };
 
+    // 重定义console.warn方法
     console.warn = (...args) => {
-      const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : arg).join(' ');
-      outputBuffer += '// 警告: ' + message + '\n';
-      output.value = code + '\n\n// 执行结果:\n' + outputBuffer;
+      const message = args.map(arg => {
+        if (typeof arg === 'object') {
+          try {
+            return JSON.stringify(arg, null, 2);
+          } catch (e) {
+            return String(arg);
+          }
+        }
+        return arg;
+      }).join(' ');
+
+      if (!message.includes('[Vue warn]')) {
+        outputBuffer += '// 警告: ' + message + '\n';
+        output.value = code + '\n\n// 执行结果:\n' + outputBuffer;
+      }
       originalConsoleWarn.apply(console, args);
     };
 
     try {
-      // 添加安全检查
+      // 安全检查
       if (code.includes('eval(') || code.includes('Function(') ||
           code.includes('document.write') || code.includes('window.location')) {
         throw new Error('代码包含不安全的操作');
@@ -1302,19 +1425,23 @@ const runCode = async () => {
       const wrappedCode = `(async () => { ${code} })()`;
       await new Function(wrappedCode)();
 
+      // 确保最终结果被正确显示
       output.value = code + '\n\n// 执行结果:\n' + outputBuffer;
     } catch (error) {
+      // 捕获并显示执行错误
       outputBuffer += '\n// 执行错误: ' + error.message;
       output.value = code + '\n\n// 执行结果:\n' + outputBuffer;
     } finally {
       // 恢复原始console方法
-      console.log = originalConsoleLog;
-      console.error = originalConsoleError;
-      console.warn = originalConsoleWarn;
+      // console.log = originalConsoleLog;
+      // console.error = originalConsoleError;
+      // console.warn = originalConsoleWarn;
     }
 
+    // 显示状态消息
     showStatus('代码执行成功!');
   } catch (error) {
+    // 处理runCode函数本身的错误
     output.value += '\n// 执行错误: ' + error.message;
     showStatus('代码执行错误: ' + error.message, 'error');
     console.error('代码执行错误:', error);
@@ -1338,9 +1465,9 @@ const showStatus = (message, type = 'success') => {
   statusType.value = type;
 
   // 3秒后自动清除状态消息
-  setTimeout(() => {
-    statusMessage.value = '';
-  }, 3000);
+  // setTimeout(() => {
+  //   statusMessage.value = '';
+  // }, 3000);
 };
 </script>