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

Merge branch 'beta' of https://git.cocorobo.cn/jack/PPT into beta

jack 2 дней назад
Родитель
Сommit
c7693aaad2

+ 2 - 2
index.html

@@ -34,7 +34,7 @@
       .first-screen-loading-spinner {
         width: 36px;
         height: 36px;
-        border: 3px solid #d14424;
+        border: 3px solid #ff9300;
         border-top-color: transparent;
         border-radius: 50%;
         box-sizing: border-box;
@@ -42,7 +42,7 @@
       }
       .first-screen-loading-text {
         margin-top: 20px;
-        color: #d14424;
+        color: #ff9300;
       }
       @keyframes spinner {
         0% {

+ 9 - 1
src/components/CollapsibleToolbar/componets/aiChat.vue

@@ -355,12 +355,20 @@ const sendAction = async (action: string) => {
 
   // 提取当前页面中 type 为 'text' 的元素的纯文本内容
   const textContents = slidesStore.currentSlide?.elements
-    .filter((element: any) => element.type === 'text')
+    .filter((element: any) => element.type === 'text' || (element.type === 'shape' && element.text && element.text.content))
     .map((textElement: any) => {
+      if (textElement.type === 'shape') {
+        // 创建一个临时元素来解析 HTML 并提取纯文本
+        const tempElement = document.createElement('div')
+        tempElement.innerHTML = textElement.text.content
+        return tempElement.textContent || tempElement.innerText || ''
+      }
       // 创建一个临时元素来解析 HTML 并提取纯文本
       const tempElement = document.createElement('div')
       tempElement.innerHTML = textElement.content
       return tempElement.textContent || tempElement.innerText || ''
+      
+
     })
     .filter(content => content.trim() !== '') || []
   console.log('textContents', textContents)

+ 4 - 2
src/components/FullscreenSpin.vue

@@ -51,14 +51,16 @@ withDefaults(defineProps<{
 .spinner {
   width: 36px;
   height: 36px;
-  border: 3px solid $themeColor;
+  // border: 3px solid $themeColor;
+  border: 3px solid #ff9300;
   border-top-color: transparent;
   border-radius: 50%;
   animation: spinner .8s linear infinite;
 }
 .text {
   margin-top: 20px;
-  color: $themeColor;
+  // color: $themeColor;
+  color: #ff9300;
 }
 @keyframes spinner {
   0% {

+ 15 - 9
src/views/Student/components/choiceQuestionDetailDialog.vue

@@ -316,6 +316,7 @@ const props = defineProps<{
   courseDetail: any;
   userId: string;
   workId: string;
+  cid: string;
 }>()
 
 const emit = defineEmits<{
@@ -731,7 +732,7 @@ const getAnalysis = () => {
   }
   console.log('props.workId', props.workId)
   const params = {
-    pid: props.workId,
+    pid: props.workId+(props.cid?','+props.cid:''),
   }
   axios.get('https://pbl.cocorobo.cn/api/pbl/select_pptAnalysisByPid?pid=' + params.pid).then(res => {
     const data = res[0]
@@ -1063,12 +1064,17 @@ const openEchatsDialog = () => {
 const getWordCloud15 = () => {
 
   return new Promise((resolve,) => {
-    const msg = `## 任务 请基于以下文本,提炼出10 - 30个关键词,用于绘制词云图。请给出相应的关键词,以及关键词出现的频次。请确保输出的关键字准确反映该段文本的主要内容和主题。
-## 要求
-1. ** 提取关键词 **:从提供的文本中提取出10 - 30个最具代表性的关键字。关键词应该涵盖该文本的主要概念、重要术语和核心主题。尽量选择多样化的关键词,避免过于集中在某一个主题或概念上。
-    2. ** 词频统计 **:计算每个关键字在文本中出现的频率。
-    3. ** 词汇大小 **:根据词频数量,确定每个关键字在词云图中的大小。词频越高,词汇大小数值越大,数值范围1 - 100。
-    4. ** 输出格式 **:输出结果应包含输出相应的关键词或元话语、对应的词频数量以及词汇大小数值,请以json格式输出,严格按照输出示例输出。
+    const msg = `## 任务
+请针对文本中学生提交的问答题回答内容进行深度分析,提炼出 10 - 30 个核心关键词,用于绘制词云图。
+## 提取准则
+1. 聚焦内容主体:仅从学生的具体回答文本中提取关键词。
+2. 严格排除杂质:禁止提取任何属于系统元数据或固定格式的词汇,包括但不限于:“课程数据”、“学生姓名”、“回答结果”、“课程标题”、“提交时间”、“作业名称”、“分数”等。
+3. 语义去重:将意思相近的词进行合并(例如“高效”与“效率高”),保留最具代表性的词条。
+4. 涵盖核心:关键词应准确反映学生回答中的核心观点、关键知识点、高频论据或情感倾向。
+## 任务要求
+1. 词频统计:计算每个有效关键字在回答内容中出现的频率。
+2. 词汇大小:根据词频,确定每个关键字在词云中的权重。词频越高,数值越大,范围 1 - 100。
+3. 输出格式:请严格按照 JSON 格式输出,包含关键词、词频及对应的词汇大小。
 
 ## 文本
 课程数据:
@@ -1076,7 +1082,7 @@ const getWordCloud15 = () => {
 - 课程学科:${props.courseDetail.name}
 当前页面答题数据(问答题):【分析重点】
 - 问答题题目:${props.showData.workDetail.json.answerQ}
-- 回答数据:${JSON.stringify(processedWorkArray.value.map((i) => ({ user: i.name, answer: i.content.answer })))}
+- 回答数据:${JSON.stringify(processedWorkArray.value.map((i) => ({ answer: i.content.answer })))}
 
 ## 输出示例
 {"tooltip":{"show":false},"series":[{"type":"wordCloud","sizeRange":[14,38],"rotationRange":[0,0],"keepAspect":false,"shape":"circle","left":"center","top":"center","right":null,"bottom":null,"width":"100%","height":"100%","rotationStep":20,"data":[{"value":"词汇大小,数值范围1-100","name":"词汇","textStyle":{"color":"词汇颜色(16进制)"}},{"value":"词汇大小,数值范围1-100","name":"词汇","textStyle":{"color":"(16进制)"}}]}]}`
@@ -1216,7 +1222,7 @@ const saveAnalysis = () => {
     return
   }
   const params = [{
-    pid: props.workId,
+    pid: props.workId+(props.cid?','+props.cid:''),
     idx: props.showData.workIndex,
     json: JSON.stringify(currentAnalysis.value.json),
   }]

+ 12 - 4
src/views/Student/index.vue

@@ -106,7 +106,7 @@
           <ScreenSlideList :style="{ width: isFullscreen ? '100%' : slideWidth2 * canvasScale + 'px', height: isFullscreen ? '100%' : slideHeight2 * canvasScale + 'px', margin: '0 auto' }" :slideWidth="isFullscreen ? slideWidth * canvasScale : slideWidth2 * canvasScale" :slideHeight="isFullscreen ? slideHeight * canvasScale : slideHeight2 * canvasScale"
             :animationIndex="0" :turnSlideToId="() => { }" :manualExitFullscreen="() => { }"  :slideIndex="slideIndex" v-show="!choiceQuestionDetailDialogOpenList.includes(slideIndex)"/>
 
-          <choiceQuestionDetailDialog v-if="choiceQuestionDetailDialogOpenList.includes(slideIndex)" :workId="workId"  :userId="props.userid" :courseDetail="courseDetail" :workArray="workArray" @changeWorkIndex="changeWorkIndex" v-model:visible="choiceQuestionDetailDialogOpenList" :showData="answerTheResultRef" :slideIndex="slideIndex" :workIndex="0" :style="{ width: isFullscreen ? '100%' : slideWidth2 * canvasScale + 'px', height: isFullscreen ? '100%' : slideHeight2 * canvasScale + 'px', margin: '0 auto' }" :slideWidth="isFullscreen ? slideWidth * canvasScale : slideWidth2 * canvasScale" :slideHeight="isFullscreen ? slideHeight * canvasScale : slideHeight2 * canvasScale"/>
+          <choiceQuestionDetailDialog v-if="choiceQuestionDetailDialogOpenList.includes(slideIndex)" :cid="props.cid" :workId="workId"  :userId="props.userid" :courseDetail="courseDetail" :workArray="workArray" @changeWorkIndex="changeWorkIndex" v-model:visible="choiceQuestionDetailDialogOpenList" :showData="answerTheResultRef" :slideIndex="slideIndex" :workIndex="0" :style="{ width: isFullscreen ? '100%' : slideWidth2 * canvasScale + 'px', height: isFullscreen ? '100%' : slideHeight2 * canvasScale + 'px', margin: '0 auto' }" :slideWidth="isFullscreen ? slideWidth * canvasScale : slideWidth2 * canvasScale" :slideHeight="isFullscreen ? slideHeight * canvasScale : slideHeight2 * canvasScale"/>
 
 
           <div class="slide-bottom" v-if="!isFullscreen">
@@ -2626,9 +2626,17 @@ const getCourseDetail = async () => {
             jsonObj.slides.forEach((slide: any, index: number) => {
               let slideContent = ''
               if (slide.elements) {
-                const textElements = slide.elements.filter((element: any) => element.type === 'text')
-                if (textElements.length > 0) {
-                  slideContent = textElements.map((element: any) => element.content).join(' ')
+                // 提取文本内容(包括普通文本和形状文本)
+                const allTextElements = slide.elements.filter((element: any) => 
+                  element.type === 'text' || (element.type === 'shape' && element.text?.content)
+                )
+                if (allTextElements.length > 0) {
+                  slideContent = allTextElements
+                    .map((element: any) => {
+                      const content = element.type === 'text' ? element.content : element.text.content
+                      return content.replace(/<[^>]*>/g, '')
+                    })
+                    .join(' ')
                 }
               }
               pptContent.push(`第${index + 1}页: ${slideContent || '内容为空'}`)