Sfoglia il codice sorgente

1、回滚:合并修建和使用模块部分
2、AI实验课:智能问答、文生图、图生图、图生视频:增加历史缓存记录
3、AI实验室:智能问答、文生图、图生图、图生视频:增加历史缓存记录

liyanbo 3 mesi fa
parent
commit
4fc557959b

+ 45 - 5
src/components/ai/image/ImageToImage.vue

@@ -172,10 +172,19 @@ import {Message} from "@/utils/message/Message.js";
 import ImageUpload from '@/components/ImageUpload/index.vue';
 
 // 导入接口
-import { getModelIdByType } from '@/api/teachers.js'
+import {getModelIdByType, ModelPlatformEnum} from '@/api/teachers.js'
 import { ModelTypeEnum } from '@/api/teachers.js'
 
-
+// 定义props
+const props = defineProps({
+  //根据需求传输
+  cacheDataKey: { type: String, default: localStorage.getItem('token') + "_imageToImage" },
+  cacheDataHistoryKey: { type: String, default: localStorage.getItem('token') + "_imageToImage_history" },
+  preDialogueList: { type: Array, default: () => []},
+  replySupplement: { type: String, default: ''},
+})
+//历史记录缓存集合
+const cacheDataHistoryList = ref([]);
 
 // 存储上传的图片
 const uploadedImage = ref('');
@@ -216,11 +225,23 @@ onMounted(async () => {
         brpProgress: 1
       });
       // 获取modelId
-    const modelRes = await getModelIdByType({ type: ModelTypeEnum.IMAGE_TO_IMAGE, platform: "DouBao" })
+    const modelRes = await getModelIdByType({ type: ModelTypeEnum.IMAGE_TO_IMAGE, platform: ModelPlatformEnum.DOUBAO })
     modelId.value = modelRes.data
   }catch(error){
     console.error('保存记录失败:', error);
   }
+
+  // 取缓存历史记录
+  let cacheDataHistoryStr = localStorage.getItem(props.cacheDataHistoryKey);
+  if (cacheDataHistoryStr) {
+    cacheDataHistoryList.value = JSON.parse(cacheDataHistoryStr) || [];
+    imageAllList.value.push(...cacheDataHistoryList.value);
+  }else{
+    // 加入预置对话
+    imageAllList.value.push(...props.preDialogueList);
+    cacheDataHistoryList.value.push(...props.preDialogueList);
+    if (cacheDataHistoryList.value.length > 0) localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
+  }
 });
 
 // 消息列表和输入内容的响应式变量
@@ -292,6 +313,11 @@ const sendMessage = async() => {
      conversationInProgress.value = false;
    }
 
+
+    // 同步历史记录缓存
+    cacheDataHistoryList.value.push(userMessage);
+    localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
+
     try {
       CreatePainting({
         "modelId": modelId.value,
@@ -357,11 +383,25 @@ const refreshWatchImages = async () => {
     } else {
       imageAllList.value.pop();
       console.log('AI生成的图片地址:', image.picUrl);
-      imageAllList.value.push({
+      let imageMsg = {
         type: 'ai',
         content: "已为您生成图片:",
         imageList: [image.picUrl],
-      })
+      }
+      imageAllList.value.push(imageMsg)
+
+
+      // 添加补充信息
+      if (!conversationInProgress.value && props.replySupplement) {
+        imageAllList.value.push({
+          type: "system",
+          content: props.replySupplement,
+        });
+      }
+
+      // 同步缓存历史记录
+      cacheDataHistoryList.value.push(imageMsg);
+      localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
     }
   })
   inProgressImageMap.value = newWatchImages

+ 49 - 10
src/components/ai/image/TextToImage.vue

@@ -170,9 +170,19 @@ import stopicon from "@/assets/icon/stopicon.png";
 import {Message} from "@/utils/message/Message.js";
 
 // 导入getModelIdByType接口
-import { getModelIdByType } from '@/api/teachers.js'
+import {getModelIdByType, ModelPlatformEnum} from '@/api/teachers.js'
 import { ModelTypeEnum } from '@/api/teachers.js'
 
+// 定义props
+const props = defineProps({
+  //根据需求传输
+  cacheDataKey: { type: String, default: localStorage.getItem('token') + "_textToImage" },
+  cacheDataHistoryKey: { type: String, default: localStorage.getItem('token') + "_textToImage_history" },
+  preDialogueList: { type: Array, default: () => []},
+  replySupplement: { type: String, default: ''},
+})
+//历史记录缓存集合
+const cacheDataHistoryList = ref([]);
 
 // 对话状态变量
 const conversationInProgress = ref(false); // 对话是否正在进行中
@@ -226,12 +236,24 @@ onMounted(async () => {
         brpProgress: 1
       });
       // 获取modelId
-    const modelRes = await getModelIdByType({ type: ModelTypeEnum.TEXT_TO_IMAGE, platform: "DouBao" })
+    const modelRes = await getModelIdByType({ type: ModelTypeEnum.TEXT_TO_IMAGE, platform: ModelPlatformEnum.DOUBAO })
     modelId.value = modelRes.data
     
   }catch(error){
     console.error('保存记录失败:', error);
   }
+
+  // 取缓存历史记录
+  let cacheDataHistoryStr = localStorage.getItem(props.cacheDataHistoryKey);
+  if (cacheDataHistoryStr) {
+    cacheDataHistoryList.value = JSON.parse(cacheDataHistoryStr) || [];
+    imageAllList.value.push(...cacheDataHistoryList.value);
+  }else{
+    // 加入预置对话
+    imageAllList.value.push(...props.preDialogueList);
+    cacheDataHistoryList.value.push(...props.preDialogueList);
+    if (cacheDataHistoryList.value.length > 0) localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
+  }
 });
 
 // 消息列表和输入内容的响应式变量
@@ -266,10 +288,11 @@ const sendMessage = async() => {
     // 先保存内容 再置空输入框
     let content = inputMessage.value;
     inputMessage.value = ''
-    imageAllList.value.push({
+    let userMsg = {
       type: 'user',
-      content: content,
-    })
+          content: content,
+    }
+    imageAllList.value.push(userMsg)
     imageAllList.value.push({
       type: 'ai',
       content: "正在为您生成图片,请稍等",
@@ -291,6 +314,10 @@ const sendMessage = async() => {
       conversationInProgress.value = false;
     }
 
+    // 同步历史记录缓存
+    cacheDataHistoryList.value.push(userMsg);
+    localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
+
     try {
       CreatePainting({
         "modelId": modelId.value,
@@ -299,9 +326,7 @@ const sendMessage = async() => {
         "height":1024
       }).then(res=>{
         console.log("生成图片",res)
-        //目前写死调用已生成的图片,全部通了后再改
         inProgressImageMap.value[res.data] = {id:res.data,status:AiImageStatusEnum.IN_PROGRESS}
-        // inProgressImageMap.value[260] = {id:260,status:AiImageStatusEnum.IN_PROGRESS}
       }).finally(() => {
         // 图片生成请求完成后更新状态
         conversationInProgress.value = false;
@@ -347,11 +372,25 @@ const refreshWatchImages = async () => {
       newWatchImages[image.id] = image
     } else {
       imageAllList.value.pop();
-      imageAllList.value.push({
-        type: 'ai',
+      let imageMsg = {
+        type: "system",
         content: "已为您生成图片:",
         imageList: [image.picUrl],
-      })
+      }
+      imageAllList.value.push(imageMsg)
+
+
+      // 添加补充信息
+      if (!conversationInProgress.value && props.replySupplement) {
+        imageAllList.value.push({
+          type: "system",
+          content: props.replySupplement,
+        });
+      }
+
+      // 同步缓存历史记录
+      cacheDataHistoryList.value.push(imageMsg);
+      localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
     }
   })
   inProgressImageMap.value = newWatchImages

+ 43 - 15
src/components/ai/text/TextToText.vue

@@ -114,8 +114,8 @@ const leftPanelRef = ref(null);
 // 定义props
 const props = defineProps({
   //根据需求传输
-  courseId: { type: Number},
-  conversationId: { type: String},
+  cacheDataKey: { type: String, default: localStorage.getItem('token') + "_textToText" },
+  cacheDataHistoryKey: { type: String, default: localStorage.getItem('token') + "_textToText_history" },
   preDialogueList: { type: Array, default: () => []},
   replySupplement: { type: String, default: ''},
 
@@ -124,7 +124,8 @@ const props = defineProps({
   personImage: { type: String},
   personIntroduce: { type: String},
 })
-
+//历史记录缓存集合
+const cacheDataHistoryList = ref([]);
 
 // 默认消息控制
 const showDefaultMessages = ref(true);
@@ -206,10 +207,23 @@ const getConversation = async (id) => {
   activeConversationModelPath.value = personImage.value;
 
 
-  // 获取对话消息列表【后面补充接口】
+  // 获取对话消息列表【后面补充接口,现在取的浏览器缓存
   // activeMessageList.value = await ChatMessageApi.getChatMessageListByConversationId(
   //     activeConversationId.value
   // )
+
+  // 取缓存历史记录
+  let cacheDataHistoryStr = localStorage.getItem(props.cacheDataHistoryKey);
+  console.log("cacheDataHistoryStr", cacheDataHistoryStr);
+  if (cacheDataHistoryStr) {
+    cacheDataHistoryList.value = JSON.parse(cacheDataHistoryStr) || [];
+    activeMessageList.value.push(...cacheDataHistoryList.value);
+  }else{
+    // 加入预置对话
+    activeMessageList.value.push(...props.preDialogueList);
+    cacheDataHistoryList.value.push(...props.preDialogueList);
+    localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
+  }
 };
 
 // 语音输入识别结果处理
@@ -308,6 +322,16 @@ const doSendMessage = async (content) => {
   }
   // 清空输入框
   prompt.value = "";
+
+  // 同步历史记录缓存
+  cacheDataHistoryList.value.push({
+    type: "user",
+    content: content,
+    createTime: new Date(),
+  });
+  localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
+
+
   // 执行发送
   await doSendMessageStream({
     conversationId: activeConversationId.value,
@@ -457,11 +481,6 @@ const messageList = computed(() => {
     };
     activeMessageList.value.push(systemMessage);
 
-    // 加入预置对话
-    props.preDialogueList.forEach(item => {
-      activeMessageList.value.push(item);
-    })
-
     return [systemMessage];
   }
   return [];
@@ -546,6 +565,16 @@ const textRoll = async () => {
           });
         }
 
+        // 同步缓存历史记录
+        if (!conversationInProgress.value) {
+          cacheDataHistoryList.value.push({
+            type: "system",
+            content: receiveMessageFullText.value,
+            createTime: new Date(),
+          });
+          localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
+        }
+
         // 不是对话中可以结束
         if (!conversationInProgress.value) {
           textRoleRunning.value = false;
@@ -597,19 +626,17 @@ onMounted(async () => {
   selectedImage.value = personImage.value;
 
   //创建对话
-  if (props.conversationId) {
-    activeConversationId.value = props.conversationId;
+  let cacheDataKeyData = localStorage.getItem(props.cacheDataKey);
+  if (cacheDataKeyData) {
+    activeConversationId.value = cacheDataKeyData;
   }else{
     // 智能问答
     CreateDialogue({ roleId: personId.value })
         .then((res) => {
           console.log("创建会话:", res);
           activeConversationId.value = res.data;
-
           //将会话存入会话缓存
-          if(props.courseId){
-            localStorage.setItem(localStorage.getItem("token") + "-" + props.courseId, activeConversationId.value)
-          }
+          if (props.cacheDataKey)localStorage.setItem(props.cacheDataKey, activeConversationId.value)
         })
         .catch((error) => {
           console.error("请求出错:", error);
@@ -617,6 +644,7 @@ onMounted(async () => {
   }
 
   await getConversation(personId.value);
+
   // 获取列表数据
   // activeMessageListLoading.value = true
 });

+ 43 - 2
src/components/ai/video/ImageToVideo.vue

@@ -136,6 +136,17 @@ import ImageUpload from '@/components/ImageUpload/index.vue';
 import { getModelIdByType } from '@/api/teachers.js'
 import { ModelTypeEnum } from '@/api/teachers.js'
 
+// 定义props
+const props = defineProps({
+  //根据需求传输
+  cacheDataKey: { type: String, default: localStorage.getItem('token') + "_imageToVideo" },
+  cacheDataHistoryKey: { type: String, default: localStorage.getItem('token') + "_imageToVideo_history" },
+  preDialogueList: { type: Array, default: () => []},
+  replySupplement: { type: String, default: ''},
+})
+//历史记录缓存集合
+const cacheDataHistoryList = ref([]);
+
 // 存储上传的图片
 const uploadedImage = ref('');
 const imageUploadRef = ref(null);
@@ -197,6 +208,18 @@ onMounted(async () => {
   }catch(error){
     console.error('保存记录失败:', error);
   }
+
+  // 取缓存历史记录
+  let cacheDataHistoryStr = localStorage.getItem(props.cacheDataHistoryKey);
+  if (cacheDataHistoryStr) {
+    cacheDataHistoryList.value = JSON.parse(cacheDataHistoryStr) || [];
+    imageAllList.value.push(...cacheDataHistoryList.value);
+  }else{
+    // 加入预置对话
+    imageAllList.value.push(...props.preDialogueList);
+    cacheDataHistoryList.value.push(...props.preDialogueList);
+    if (cacheDataHistoryList.value.length > 0) localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
+  }
 });
 
 // 消息列表和输入内容的响应式变量
@@ -264,6 +287,10 @@ const sendMessage = async() => {
       conversationInProgress.value = false;
     }
 
+    // 同步历史记录缓存
+    cacheDataHistoryList.value.push(userMessage);
+    localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
+
     try {
       CreateVideo({
         "modelId": modelId.value,
@@ -331,11 +358,25 @@ const refreshWatchImages = async () => {
     } else {
       imageAllList.value.pop();
       console.log('AI生成的视频地址:', image.videoUrl);
-      imageAllList.value.push({
+      let videoMsg = {
         type: 'ai',
         content: "已为您生成视频:",
         imageList: [image.videoUrl],
-      })
+      }
+      imageAllList.value.push(videoMsg)
+
+
+      // 添加补充信息
+      if (!conversationInProgress.value && props.replySupplement) {
+        imageAllList.value.push({
+          type: "system",
+          content: props.replySupplement,
+        });
+      }
+
+      // 同步缓存历史记录
+      cacheDataHistoryList.value.push(videoMsg);
+      localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
     }
   })
   inProgressImageMap.value = newWatchImages

+ 80 - 83
src/components/blockly/MapGame.vue

@@ -4,11 +4,11 @@
     <div class="left-container">
       <!-- 线路切换按钮 -->
       <div class="route-buttons">
-        <button 
-          v-for="(route, index) in parsedRouteList" 
-          :key="index"
-          class="game-badge"
-          :class="{ 'active': currentRouteIndex === index }"
+        <button
+            v-for="(route, index) in parsedRouteList"
+            :key="index"
+            class="game-badge"
+            :class="{ 'active': currentRouteIndex === index }"
         >
           {{ gameSort }}{{ index + 1 }}
         </button>
@@ -16,7 +16,7 @@
     </div>
   </div>
 
-<!--  中间地图组件部分-->
+  <!--  中间地图组件部分-->
   <div class="content">
     <!-- 地图显示区域 -->
     <div class="map-section">
@@ -42,7 +42,7 @@
               class="walkable-point"
               :style="getPointStyle(point)"
           >
-</div>
+          </div>
 
           <!-- 玩家角色 -->
           <div
@@ -87,14 +87,14 @@
       <div class="workspace-section">
         <div class="controls">
           <button id="runCode" @click="resetPlayer();runCode();" :disabled="isRunning">运行代码</button>
-            <!-- <button @click="generatePythonCode">生成Python代码</button>-->
+          <!-- <button @click="generatePythonCode">生成Python代码</button>-->
           <button @click="resetPlayer" >重置玩家</button>
           <button @click="clearWorkspace">清空工作区</button>
         </div>
 
-<!--        工具箱-->
+        <!--        工具箱-->
         <div id="toolbox"></div>
-<!--        工作区-->
+        <!--        工作区-->
         <div id="blocklyDiv"></div>
       </div>
     </div>
@@ -313,14 +313,14 @@ const parsedRouteList = computed(() => {
   try {
     const routeData = typeof props.routeList === 'string' ? JSON.parse(props.routeList) : props.routeList;
     const routes = Array.isArray(routeData) ? routeData : [];
-    
+
     // 初始化路线通过状态
     if (routePassedStatus.value.length === 0 && routes.length > 0) {
       routePassedStatus.value = routes.map((_, index) => index === 0); // 第一条路线默认可用
     }
-    
+
     return routes;
-} catch (error) {
+  } catch (error) {
     console.error('解析routeList失败:', error);
     return [];
   }
@@ -600,29 +600,29 @@ const fetchGameData = async () => {
 const switchRoute = (index) => {
   // 检查路线是否可用
   if (index < 0 || index >= parsedRouteList.value.length || !isRouteAvailable(index)) return;
-  
+
   currentRouteIndex.value = index;
   const route = parsedRouteList.value[index];
-  
+
   // 更新人物朝向
   if (route.direction !== undefined) {
     playerInitialDirection.value = route.direction;
     gameState.player.direction = route.direction;
   }
-  
+
   // 更新开始坐标
   if (route.startPoint) {
     const startPoint = typeof route.startPoint === 'string' ? JSON.parse(route.startPoint) : route.startPoint;
     gameState.mapData.startPoint = { x: startPoint.x, y: startPoint.y };
     gameState.player.position = { x: startPoint.x, y: startPoint.y };
   }
-  
+
   // 更新结束坐标
   if (route.endPoint) {
     const endPoint = typeof route.endPoint === 'string' ? JSON.parse(route.endPoint) : route.endPoint;
     gameState.mapData.endPoint = { x: endPoint.x, y: endPoint.y };
   }
-  
+
   // 重新初始化可行走点集合【目前没有单独配置路线的可行走集合,一张地图通用】
   // initWalkablePointsSet();
 };
@@ -667,12 +667,12 @@ const updateGameStateFromData = (gameData) => {
     if (gameData.routeList) {
       gameState.mapData.routeList = JSON.parse(gameData.routeList);
     }
-    
+
     // 初始加载时选中第一条线路
     if (parsedRouteList.value.length > 0) {
       switchRoute(0);
     }
-    
+
     // 重新初始化可行走点集合
     initWalkablePointsSet();
   } catch (error) {
@@ -1223,8 +1223,49 @@ window.pickupItem = async function()  {
 
 // 使用物品函数
 window.useItem = async function() {
-  // 调用修建函数,修建函数已经包含了使用物品的逻辑
-  await window.construct();
+  if (shouldStopExecution || isColliding.value || isSliding.value) {
+    return;
+  }
+
+  //取人物当前位置
+  let x = playerPosition.value.x;
+  let y = playerPosition.value.y;
+  let tileMap = walkablePointsMap.get(`${x},${y}`);
+
+  // 判断当前位置是否有特殊需求
+  if (tileMap && tileMap.type === BLOCKLY_MAP_TYPE_DICT.TASK) {
+    // 检查玩家是否携带了需要的物品
+    const requiredItems = tileMap.type;
+
+    let hasRequiredItem = false;
+    let itemIndex = -1;
+
+    if (gameState.player.carriedItems.length > 0) {
+      hasRequiredItem = true;
+      itemIndex = 0;
+    }
+
+    if (hasRequiredItem) {
+
+      // 获取要使用的物品
+      const itemToUse = gameState.player.carriedItems[itemIndex];
+      // 从携带物品中移除已使用的物品
+      gameState.player.carriedItems.splice(itemIndex, 1);
+      // 执行物品使用动画,传递finishAnimation
+      await animateItemUse(itemToUse, itemIndex, tileMap.finishAnimation);
+
+      // 使用物品成功
+      showGameMessage(tileMap.finishedTip || CONFIG.TIPS.USE_ITEM_SUCCESS, 'success');
+
+    } else {
+      // 提示缺少所需物品
+      showGameMessage(tileMap.unfinishedTip || CONFIG.TIPS.USE_SPECIAL_ITEM, 'warning');
+    }
+  } else {
+    showGameMessage(CONFIG.TIPS.NO_USE_ITEM, 'info');
+  }
+
+  await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.ACTION_DELAY));
 }
 
 // 暂停函数
@@ -1288,59 +1329,15 @@ window.playSound = async function() {
   await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.PALY_MP3_TIMES));
 };
 
-// 修建函数(通用任务处理函数)
+// 修建函数
 window.construct = async function() {
   if (shouldStopExecution || isColliding.value || isSliding.value) {
     return;
   }
 
-  //取人物当前位置
-  let x = playerPosition.value.x;
-  let y = playerPosition.value.y;
-  let tileMap = walkablePointsMap.get(`${x},${y}`);
-  
-  // 判断当前位置是否有特殊需求
-  if (tileMap && tileMap.type === BLOCKLY_MAP_TYPE_DICT.TASK) {
-    // 检查是否需要物品
-    if (tileMap.needItem) {
-      // 检查玩家是否携带了需要的物品
-      let hasRequiredItem = false;
-      let itemIndex = -1;
-      
-      // 查找玩家携带的物品
-      for (let i = 0; i < gameState.player.carriedItems.length; i++) {
-        const item = gameState.player.carriedItems[i];
-        // 检查物品是否匹配任务需求
-        if (item.type === tileMap.needItem || !tileMap.needItem) {
-          hasRequiredItem = true;
-          itemIndex = i;
-          break;
-        }
-      }
-      
-      if (hasRequiredItem) {
-        // 获取要使用的物品
-        const itemToUse = gameState.player.carriedItems[itemIndex];
-        // 从携带物品中移除已使用的物品
-        gameState.player.carriedItems.splice(itemIndex, 1);
-        // 执行物品使用动画
-        await animateItemUse(itemToUse, itemIndex, tileMap.finishAnimation);
-        // 使用物品成功
-        showGameMessage(tileMap.finishedTip || CONFIG.TIPS.USE_ITEM_SUCCESS, 'success');
-      } else {
-        // 提示缺少所需物品
-        showGameMessage(tileMap.unfinishedTip || CONFIG.TIPS.USE_SPECIAL_ITEM, 'warning');
-      }
-    } else {
-      // 不需要物品的任务,直接处理
-      await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.TEMP_ITEM_FADE_DURATION));
-      processingSpecialTasksDisappearing();
-    }
-  } else {
-    showGameMessage(CONFIG.TIPS.NO_USE_ITEM, 'info');
-  }
-
-  await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.ACTION_DELAY));
+  await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.TEMP_ITEM_FADE_DURATION));
+  //处理特殊任务消失
+  processingSpecialTasksDisappearing()
 };
 
 // 当经过指定形状时执行的函数(返回布尔值,可作为参数使用)
@@ -1356,7 +1353,7 @@ window.whenPassed = function(shape) {
 
   // 检查当前位置的瓦片是否匹配指定形状
   const isMatch = tileMap && tileMap.mark && tileMap.mark.toLowerCase() === shape;
-  
+
   return isMatch;
 };
 
@@ -1387,7 +1384,7 @@ window.isFinish = async function() {
     // 统计其中status为true的完成任务数||完成拾取物品的人物总数
     const completedTasks = gameState.mapData.walkablePoints.filter(
         p => p.type === BLOCKLY_MAP_TYPE_DICT.TASK && p.status === true
-                || p.type === BLOCKLY_MAP_TYPE_DICT.ITEM && p.must === true && p.status === true
+            || p.type === BLOCKLY_MAP_TYPE_DICT.ITEM && p.must === true && p.status === true
     ).length;
 
     //blockly总星星数量
@@ -1426,14 +1423,14 @@ async function moveStep(newX, newY, moveDirection = 0){
 
   // 检查是否可以移动
   if (walkablePointsMap.has(`${newX},${newY}`)) {
-      // 移动前处理方块类型逻辑
-      await switchMapType(0);
+    // 移动前处理方块类型逻辑
+    await switchMapType(0);
 
-      // 使用平滑移动动画
-      await smoothMoveTo(newX, newY);
+    // 使用平滑移动动画
+    await smoothMoveTo(newX, newY);
 
-      // 移动后处理方块类型逻辑
-      await switchMapType(1, moveDirection);
+    // 移动后处理方块类型逻辑
+    await switchMapType(1, moveDirection);
 
     await new Promise(resolve => setTimeout(resolve, CONFIG.DELAY.ACTION_DELAY));
   } else {
@@ -2312,11 +2309,11 @@ onUnmounted(() => {
   box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
 }
 .previous-btn {
-    background-color: rgba(255, 255, 255, 0.8);
-    color: #333;
+  background-color: rgba(255, 255, 255, 0.8);
+  color: #333;
 }
 .previous-btn:hover {
-    background-color: rgba(255, 255, 255, 0.9);
+  background-color: rgba(255, 255, 255, 0.9);
 }
 .next-btn {
   background: #5fb5dc;
@@ -2478,8 +2475,8 @@ onUnmounted(() => {
   background: linear-gradient(145deg, rgba(240, 240, 240, 0.8), rgba(200, 200, 200, 0.6));
   border: 4px solid rgba(100, 100, 100, 0.8);
   box-shadow:
-    0 0 20px rgba(0, 0, 0, 0.3),
-    inset 0 0 20px rgba(0, 0, 0, 0.1);
+      0 0 20px rgba(0, 0, 0, 0.3),
+      inset 0 0 20px rgba(0, 0, 0, 0.1);
   position: relative;
   display: flex;
   justify-content: center;

+ 5 - 7
src/views/laboratory/ExperimentalCourses.vue

@@ -316,13 +316,11 @@ const handleCourseItemClick = (item, index) => {
   }
 
   // 直接使用item中的信息,避免再次查找
-  if (item.contentType === 'video' || item.contentType === 'aiTextToText') {
-    showVideo.value = true
-    selectedCourseData.value = {
-      ...resData.value.find(course => course.id === item.id),
-      ztId: originalCourseId.value,
-      isDisabled: isDisabled.value
-    }
+  showVideo.value = true
+  selectedCourseData.value = {
+    ...resData.value.find(course => course.id === item.id),
+    ztId: originalCourseId.value,
+    isDisabled: isDisabled.value
   }
 }
 

+ 10 - 3
src/views/laboratory/ExperimentalInterface.vue

@@ -48,23 +48,29 @@
 
           <!--文生文-->
           <TextToText class="contentClass" v-if="course.courseContentType === 'aiTextToText'" ref="aiTextToText"
-                      :courseId="course.id"
-                      :conversationId="course.conversationId"
+                      :cacheDataKey="course.cacheDataKey"
+                      :cacheDataHistoryKey="course.cacheDataHistoryKey"
                       :preDialogueList="course.aiPreDialogueList"
                       :replySupplement="course.aiReplySupplement"></TextToText>
 
           <!--文生图-->
           <TextToImage class="contentClass" v-if="course.courseContentType === 'aiTextToImage'" ref="aiTextToImage"
+                       :cacheDataKey="course.cacheDataKey"
+                       :cacheDataHistoryKey="course.cacheDataHistoryKey"
                        :preDialogueList="course.aiPreDialogueList"
                        :replySupplement="course.aiReplySupplement"></TextToImage>
 
           <!--图生图-->
           <ImageToImage class="contentClass" v-if="course.courseContentType === 'aiImageToImage'" ref="aiImageToImage"
+                        :cacheDataKey="course.cacheDataKey"
+                        :cacheDataHistoryKey="course.cacheDataHistoryKey"
                         :preDialogueList="course.aiPreDialogueList"
                         :replySupplement="course.aiReplySupplement"></ImageToImage>
 
           <!--图生视频-->
           <ImageToVideo class="contentClass" v-if="course.courseContentType === 'aiImageToVideo'" ref="aiImageToVideo"
+                        :cacheDataKey="course.cacheDataKey"
+                        :cacheDataHistoryKey="course.cacheDataHistoryKey"
                         :preDialogueList="course.aiPreDialogueList"
                         :replySupplement="course.aiReplySupplement"></ImageToVideo>
           
@@ -325,7 +331,8 @@ const handleParentCourseData = (courseData = props.courseData) => {
   courseId.value = course.value.id
 
   // 设置对话ID
-  course.value.conversationId = localStorage.getItem(localStorage.getItem("token") + "-" + course.value.id)
+  course.value.cacheDataKey = localStorage.getItem("token") + "-" + course.value.id
+  course.value.cacheDataHistoryKey = course.value.cacheDataKey + "_history"
 
   // 如果有配置,禁用视频检查
   if (courseData.isDisabled) {