|
|
@@ -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">×</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>
|
|
|
|