Просмотр исходного кода

feat: 添加批量生成互动工具的未处理选区提示逻辑

1. 新增多语言版本的未处理选区提示文案
2. 优化子页面工具展示的条件渲染和数据处理
3. 新增AI聊天触发批量任务前的未处理工具校验逻辑
4. 调整AI聊天的流式请求为非流式调用
5. 自动跳转至第一个包含工具的幻灯片页面
lsc 1 день назад
Родитель
Сommit
e176433aa6

+ 77 - 20
src/components/CollapsibleToolbar/componets/aiChat.vue

@@ -212,7 +212,7 @@
 <script lang="ts" setup>
 <script lang="ts" setup>
 import { ref, onMounted, useTemplateRef, nextTick, watch } from 'vue'
 import { ref, onMounted, useTemplateRef, nextTick, watch } from 'vue'
 import { chat_no_stream, chat_stream, getAgentModel, chat_no_stream2 } from '@/tools/aiChat'
 import { chat_no_stream, chat_stream, getAgentModel, chat_no_stream2 } from '@/tools/aiChat'
-import { useSlidesStore } from '@/store'
+import { useSlidesStore, useMainStore } from '@/store'
 import { lang } from '@/main'
 import { lang } from '@/main'
 import MarkdownIt from 'markdown-it'
 import MarkdownIt from 'markdown-it'
 import { getWorkPageId } from '@/services/course'
 import { getWorkPageId } from '@/services/course'
@@ -435,6 +435,7 @@ const sendQuickAction = (action: string) => {
 import { v4 as uuidv4 } from 'uuid'
 import { v4 as uuidv4 } from 'uuid'
 const session_name = ref('')
 const session_name = ref('')
 const slidesStore = useSlidesStore()
 const slidesStore = useSlidesStore()
+const mainStore = useMainStore()
 const gType = ref('chat')
 const gType = ref('chat')
 
 
 const sendAction = async (action: string) => {
 const sendAction = async (action: string) => {
@@ -480,7 +481,27 @@ const sendAction = async (action: string) => {
         gType: gType.value,
         gType: gType.value,
         isGenerate: false
         isGenerate: false
       }
       }
+      let isHave = 1
+      for (let i = 0; i < slidesStore.slides.length; i++) {
+        const slide = slidesStore.slides[i]
+        if (slide.toolsArray && slide.toolsArray.length > 0) {
+          const hasUnprocessed = slide.toolsArray.length
+          if (hasUnprocessed) {
+            isHave = 2
+            break
+          }
+        }
+      }
+      if (isHave == 2) {
+        messages.value.at(-1).aiContent = lang.ssBatchInteractiveWebDesc3
+        messages.value.at(-1).loading = false
+        chatLoading.value = false
+        messages.value.at(-1).chatloading = false
+        return
+      }
+      
       messages.value.at(-1).aiContent = lang.ssBatchInteractiveWebDesc
       messages.value.at(-1).aiContent = lang.ssBatchInteractiveWebDesc
+      
       // messages.value.at(-1).loading = false
       // messages.value.at(-1).loading = false
       // messages.value.at(-1).chatloading = false
       // messages.value.at(-1).chatloading = false
       // chatLoading.value = false
       // chatLoading.value = false
@@ -515,11 +536,31 @@ const sendAction = async (action: string) => {
         gType: 'trigger_batch_tool',
         gType: 'trigger_batch_tool',
         isGenerate: false
         isGenerate: false
       }
       }
+      let isHave = 1
+      for (let i = 0; i < slidesStore.slides.length; i++) {
+        const slide = slidesStore.slides[i]
+        if (slide.toolsArray && slide.toolsArray.length > 0) {
+          const hasUnprocessed = slide.toolsArray.length
+          if (hasUnprocessed) {
+            isHave = 2
+            break
+          }
+        }
+      }
+      if (isHave == 2) {
+        messages.value.at(-1).aiContent = lang.ssBatchInteractiveWebDesc3
+        messages.value.at(-1).loading = false
+        chatLoading.value = false
+        messages.value.at(-1).chatloading = false
+        return
+      }
+      
       messages.value.at(-1).aiContent = lang.ssBatchInteractiveWebDesc
       messages.value.at(-1).aiContent = lang.ssBatchInteractiveWebDesc
+      
       // messages.value.at(-1).loading = false
       // messages.value.at(-1).loading = false
       // chatLoading.value = false
       // chatLoading.value = false
       // messages.value.at(-1).chatloading = false
       // messages.value.at(-1).chatloading = false
-      return
+      // return
     }
     }
   }
   }
   else {
   else {
@@ -635,25 +676,33 @@ const sendAction = async (action: string) => {
   }
   }
 
 
   if (gType.value === 'trigger_batch_tool') {
   if (gType.value === 'trigger_batch_tool') {
-    chat_stream(prompt, agentid, props.userid || '', lang.lang, async (event) => {
-      if (event.type === 'message') {
-        messages.value.at(-1).jsonData.aiContent = md.render(event.data)
-        messages.value.at(-1).loading = false
+    const result = chat_no_stream(prompt, agentid, props.userid || '', lang.lang)
+    streamController.value = result
+    console.log(result)
+    const content = await result.promise
+    messages.value.at(-1).jsonData.aiContent = content
+    console.log('event.data', content)
+    generate(messages.value.at(-1))
+
+    // chat_stream(prompt, agentid, props.userid || '', lang.lang, async (event) => {
+    //   if (event.type === 'message') {
+    //     messages.value.at(-1).jsonData.aiContent = md.render(event.data)
+    //     messages.value.at(-1).loading = false
         
         
-      }
-      else if (event.type === 'messageEnd') {
-        messages.value.at(-1).jsonData.aiContent = md.render(event.data)
-        console.log('event.data', event.data)
-        generate(messages.value.at(-1))
-
-      }
-    }, session_name.value, messages.value.at(-1).sourceFiles?.map(file => file.id).filter(Boolean)).then(controller => {
-      streamController.value = controller
-    }).catch(err => {
-      chatLoading.value = false
-      console.log('err', err)
-      stopMessage()
-    })
+    //   }
+    //   else if (event.type === 'messageEnd') {
+    //     messages.value.at(-1).jsonData.aiContent = md.render(event.data)
+    //     console.log('event.data', event.data)
+    //     generate(messages.value.at(-1))
+
+    //   }
+    // }, session_name.value, messages.value.at(-1).sourceFiles?.map(file => file.id).filter(Boolean)).then(controller => {
+    //   streamController.value = controller
+    // }).catch(err => {
+    //   chatLoading.value = false
+    //   console.log('err', err)
+    //   stopMessage()
+    // })
     return
     return
 
 
   }
   }
@@ -816,6 +865,14 @@ const generate = (message: ChatMessage) => {
           slidesStore.updateSlide({ toolsArray: item.tools }, slide.id)
           slidesStore.updateSlide({ toolsArray: item.tools }, slide.id)
         }
         }
       }
       }
+      
+      const firstPageWithTools = slidesStore.slides.findIndex((slide: any) => 
+        slide.toolsArray && slide.toolsArray.length > 0
+      )
+      if (firstPageWithTools !== -1) {
+        slidesStore.updateSlideIndex(firstPageWithTools)
+        mainStore.setChildPageState(true, slidesStore.slides[firstPageWithTools].toolsArray || [], firstPageWithTools || 0)
+      }
     })
     })
   }
   }
 }
 }

+ 14 - 4
src/views/Editor/Canvas/ChildPageDisplay.vue

@@ -18,15 +18,16 @@
       </div>
       </div>
     </div>
     </div>
 
 
-    <div class="child-page-body">
+    <div class="child-page-body" v-if="toolsJson?.url === toolsArray[selectedToolIndex]?.url">
       <div class="question-area">
       <div class="question-area">
         <iframe
         <iframe
-          :src="toolsArray[selectedToolIndex]?.url + '&isSet=2' || ''"
+          ref="iframeRef"
+          :src="toolsJson?.url + '&isSet=2'"
           frameborder="0"></iframe>
           frameborder="0"></iframe>
       </div>
       </div>
 
 
-      <div class="side-panel" v-if="!toolsArray[selectedToolIndex].isSet">
-         <button class="side-btn primary" @click="saveTool(toolsArray[selectedToolIndex].url || '', currentToolType, selectedToolIndex)">{{ lang.ssKeep }}</button>
+      <div class="side-panel" v-if="!toolsJson.isSet">
+         <button class="side-btn primary" @click="saveTool(toolsJson.url || '', currentToolType, selectedToolIndex)">{{ lang.ssKeep }}</button>
         <button class="side-btn secondary" @click="discardTool(selectedToolIndex)">{{ lang.ssDiscard }}</button>
         <button class="side-btn secondary" @click="discardTool(selectedToolIndex)">{{ lang.ssDiscard }}</button>
         <div class="divider"></div>
         <div class="divider"></div>
         <button class="side-btn link" @click="keepAllTools">{{ lang.ssKeepAll }}</button>
         <button class="side-btn link" @click="keepAllTools">{{ lang.ssKeepAll }}</button>
@@ -54,6 +55,12 @@ const toolsArray = childPageToolsArray.value
 const selectedToolIndex = ref(0)
 const selectedToolIndex = ref(0)
 const agentid2 = ref('f86aa63c-b7b7-4d03-9b37-b59f116d36f3')// 生成内容
 const agentid2 = ref('f86aa63c-b7b7-4d03-9b37-b59f116d36f3')// 生成内容
 const loading = ref(true)
 const loading = ref(true)
+const iframeRef = ref<HTMLIFrameElement>()
+
+
+const toolsJson = computed(() => {
+  return toolsArray[selectedToolIndex.value] || {}
+})
 
 
 const formatHint = (str: string, count: number) => {
 const formatHint = (str: string, count: number) => {
   return str.replace('{0}', String(count))
   return str.replace('{0}', String(count))
@@ -61,6 +68,9 @@ const formatHint = (str: string, count: number) => {
 
 
 const selectTool = (index: number) => {
 const selectTool = (index: number) => {
   selectedToolIndex.value = index
   selectedToolIndex.value = index
+  if (iframeRef.value) {
+    iframeRef.value.contentWindow?.location.reload()
+  }
   console.log('👶 选中工具:', toolsArray[index])
   console.log('👶 选中工具:', toolsArray[index])
 }
 }
 
 

+ 1 - 0
src/views/lang/cn.json

@@ -932,6 +932,7 @@
   "ssBatchInteractiveWeb": "为课件批量生成互动工具",
   "ssBatchInteractiveWeb": "为课件批量生成互动工具",
   "ssBatchInteractiveWebDesc": "已收到「新课程」的批量生成任务,正在读取资料来源...",
   "ssBatchInteractiveWebDesc": "已收到「新课程」的批量生成任务,正在读取资料来源...",
   "ssBatchInteractiveWebDesc2": "工具待选区,请在底部待选区页面处理「保留/丢弃/全部保留」。",
   "ssBatchInteractiveWebDesc2": "工具待选区,请在底部待选区页面处理「保留/丢弃/全部保留」。",
+  "ssBatchInteractiveWebDesc3": "还存在未处理的待选区,请先处理待选区后再批量生成互动工具。",
   "ssChildPageLabel": "待选页",
   "ssChildPageLabel": "待选页",
   "ssWaitSelection": "待选区",
   "ssWaitSelection": "待选区",
   "ssWaitSelectionHint": "此位置有 {0} 个候选工具",
   "ssWaitSelectionHint": "此位置有 {0} 个候选工具",

+ 2 - 1
src/views/lang/en.json

@@ -932,7 +932,8 @@
   "ssBatchInteractiveWeb": "Batch Generate Interactive Web Tools",
   "ssBatchInteractiveWeb": "Batch Generate Interactive Web Tools",
   "ssBatchInteractiveWebDesc": "Received a batch generation task for the new course. Reading the source materials...",
   "ssBatchInteractiveWebDesc": "Received a batch generation task for the new course. Reading the source materials...",
   "ssBatchInteractiveWebDesc2": "Tools are pending selection. Please process in the bottom selection page.",
   "ssBatchInteractiveWebDesc2": "Tools are pending selection. Please process in the bottom selection page.",
-  "ssChildPageLabel": "Child Page",
+  "ssBatchInteractiveWebDesc3": "There are still unprocessed wait selections. Please process the wait selections first.",
+   "ssChildPageLabel": "Child Page",
   "ssWaitSelection": "Wait Selection",
   "ssWaitSelection": "Wait Selection",
   "ssWaitSelectionHint": "There are {0} candidate tools",
   "ssWaitSelectionHint": "There are {0} candidate tools",
   "ssCandidate": "Candidate",
   "ssCandidate": "Candidate",

+ 1 - 0
src/views/lang/hk.json

@@ -932,6 +932,7 @@
   "ssBatchInteractiveWeb": "為課件批量生成互動工具",
   "ssBatchInteractiveWeb": "為課件批量生成互動工具",
   "ssBatchInteractiveWebDesc": "已收到「新课程」的批量生成任务,正在读取资料来源...",
   "ssBatchInteractiveWebDesc": "已收到「新课程」的批量生成任务,正在读取资料来源...",
   "ssBatchInteractiveWebDesc2": "工具待选区,请在底部待选区页面处理「保留/丢弃/全部保留」。",
   "ssBatchInteractiveWebDesc2": "工具待选区,请在底部待选区页面处理「保留/丢弃/全部保留」。",
+  "ssBatchInteractiveWebDesc3": "还存在未处理的待选区,请先处理待选区后再批量生成互动工具。",
   "ssChildPageLabel": "待選頁",
   "ssChildPageLabel": "待選頁",
   "ssWaitSelection": "待選區",
   "ssWaitSelection": "待選區",
   "ssWaitSelectionHint": "此位置有 {0} 個候選工具",
   "ssWaitSelectionHint": "此位置有 {0} 個候選工具",