Преглед изворни кода

refactor(student): 优化两处异常重试逻辑与AI分析功能

1. 为addOp3的catch块添加10秒延迟重试,避免频繁请求
2. 重构choiceQuestionDetailDialog的AI分析函数:
   - 重命名函数与绑定事件为统一的832后缀
   - 新增完整的六顶思考帽教学分析逻辑与状态管理
   - 补充调试日志与结果保存逻辑
lsc пре 3 дана
родитељ
комит
348a4ccf60

+ 174 - 3
src/views/Student/components/choiceQuestionDetailDialog.vue

@@ -921,7 +921,7 @@
         </div>
 <!-- processedWorkArray.length > 0 && lookWorkData === null && props.showData.toolType == '832' && props.roleType == 1 -->
         <div class="aiAnalysis" style="margin-top:1rem ;"
-            v-if="false"
+            v-if="processedWorkArray.length > 0 && lookWorkData === null && props.showData.toolType == '832' && props.roleType == 1"
             @click.stop="clickContent(false)">
             <div class="ai_header">
               <div class="ai_title">
@@ -935,7 +935,7 @@
                 </svg>{{ lang.ssAnalysis }}
               </div>
               <div class="ai_refresh" :class="{ 'disabled': currentAnalysis && currentAnalysis.loading }"
-                @click.stop="aiAnalysisRefresh831()">
+                @click.stop="aiAnalysisRefresh832()">
                 {{ lang.ssAIGenerate }}
                 <svg viewBox="0 0 1024 1024" width="200" height="200">
                   <path
@@ -2789,7 +2789,7 @@ ${a.content}\n`
 }
 
 // ai应用
-const aiAnalysisRefresh831 = async () => {
+const aiAnalysisRefresh831 = () => {
 
   let chatMsg = ``
   console.log('processedWorkArray.value', processedWorkArray.value)
@@ -2856,6 +2856,177 @@ ${chatMsg}`
 
 
 
+  console.log('workUrl', props.workUrl)
+  console.log('ai应用提示词', msg)
+  if (!currentAnalysis.value) {
+    aiAnalysisData.value.push({
+      pid: props.workId + (props.cid ? ',' + props.cid : ''),
+      index: props.showData.workIndex,
+      loading: true,
+      json: { text: '', echartsData: '' },
+      noEnd: true,
+      update_at: '',
+      create_at: '',
+    })
+  }
+  else {
+    aiAnalysisData.value.find((item: any) => {
+      return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
+    }).loading = true
+    aiAnalysisData.value.find((item: any) => {
+      return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
+    }).json = { text: '', echartsData: '' }
+  }
+
+  chat_stream(msg, 'a7741704-ba56-40b7-a6b8-62a423ef9376', props.userId, lang.lang, (event) => {
+    if (event.type === 'message') {
+      aiAnalysisData.value.find((item: any) => {
+        return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
+      }).json.text = md.render(event.data)
+
+      aiAnalysisData.value.find((item: any) => {
+        return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
+      }).loading = false
+    }
+    else if (event.type === 'messageEnd') {
+      aiAnalysisData.value.find((item: any) => {
+        return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
+      }).json.text = md.render(event.data)
+      aiAnalysisData.value.find((item: any) => {
+        return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
+      }).noEnd = false
+      aiAnalysisData.value.find((item: any) => {
+        return item.pid === props.workId + (props.cid ? ',' + props.cid : '') && item.index === props.showData.workIndex
+      }).update_at = new Date().toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }).replace(/\//g, '-')
+      saveAnalysis()
+    }
+  }, '', [], 'open-qwen-plus-latest').catch(err => {
+    console.log('err', err)
+  })
+}
+
+// ai应用
+const aiAnalysisRefresh832 = () => {
+
+  let chatMsg = ``
+  console.log('processedWorkArray.value', processedWorkArray.value)
+  const hatNames: Record<string, string> = {
+    white: '白帽|事实与信息',
+    red: '红帽|感受与直觉',
+    black: '黑帽|风险与问题',
+    yellow: '黄帽|价值与机会',
+    green: '绿帽|创意与可能性',
+    blue: '蓝帽|总结与推进',
+  }
+  processedWorkArray.value.forEach((i) => {
+    if (typeof i.content === 'object') {
+      const c = i.content
+      const studentName = i.name || ''
+      const isGroup = c.members && c.members.length > 0
+      const memberNames = isGroup ? c.members.map((m: any) => typeof m === 'object' ? (m.name || '') : m) : []
+      const submitter = isGroup ? `${studentName}(小组成员:${memberNames.join('、')})` : studentName
+      if (c.scenario) {
+        chatMsg += `\n${submitter} - 讨论场景:\n${c.scenario}\n`
+      }
+      const hats = c.hats || []
+      const hatContent = c.c || c.hatContent || {}
+      hats.forEach((hat: string) => {
+        const label = hatNames[hat] || hat
+        const content = hatContent[hat] || ''
+        if (content) {
+          chatMsg += `\n${submitter} - ${label}:\n${content}\n`
+        }
+      })
+    }
+  })
+
+  const msg = `# CONTEXT #
+课程数据:
+- 课程名称:${props.courseDetail.title}
+- 课程学科:${props.courseDetail.name}
+- 需要提交人数:${props.showData.workArray.length + props.showData.unsubmittedStudents.length}
+- 已提交人数:${props.showData.workArray.length}
+你是一名教学分析助手。请根据全班学生或各小组提交的「六顶思考帽」讨论内容,从班级整体视角进行简洁分析,帮助教师快速了解学生在不同思考方式下的主要观点、分歧与值得继续讨论的问题。
+本次活动不一定使用完整的六顶思考帽。教师可能只配置其中 3 顶、4 顶或其他组合。
+你必须以本次活动实际配置和学生实际提交的思考帽为准,只分析本次活动中启用的思考帽,不要自行补充未启用的帽子。
+提交内容可能有两种形式:
+个人提交:每名学生分别填写本次活动配置的一个或多个思考帽。
+小组提交:以小组为单位提交,内容中可能包含小组成员姓名、每位成员负责的思考帽,以及对应讨论内容。
+六顶思考帽的含义如下,仅用于识别和分析本次实际启用的帽子:
+白帽|事实与信息
+关注学生提出的事实、数据、已知信息,以及认为仍需补充的信息。
+红帽|感受与直觉
+关注学生表达的感受、直觉、第一反应、喜欢或担忧。
+黑帽|风险与问题
+关注学生发现的问题、限制、风险、困难或可能失败的原因。
+黄帽|价值与机会
+关注学生发现的优点、价值、机会、积极影响或可行之处。
+绿帽|创意与可能性
+关注学生提出的新想法、替代方案、改进方式或不同可能性。
+蓝帽|总结与推进
+关注学生对讨论的总结、观点整合、下一步行动、需要进一步解决的问题。
+分析要求:
+只分析本次活动实际配置的思考帽。
+未配置的思考帽不要输出,也不要视为“缺失”“未作答”或“思考不足”。
+对于已经配置的思考帽,统计实际有效参与情况。
+如果是个人提交,统计有效作答人数及占全班比例,例如“18人,75%”。
+如果是小组提交,优先统计有效参与小组数及占全部提交小组比例,例如“5/6组,83%”;如数据中可以明确判断参与该帽子的学生人数,可补充人数,例如“5/6组,8人参与”。
+如果某顶帽子已配置,但无人或无小组实际提交有效内容,则不要输出该帽子。
+学生或小组未填写某顶已配置的帽子,不代表缺乏这种思维能力,禁止据此推断。
+将意思相近的观点合并归纳,优先呈现班级或多个小组反复出现的共性观点。
+如果不同学生或小组之间存在明显不同观点,可简短呈现主要分歧,不必强行形成统一结论。
+区分“学生明确提出的内容”和你的推断,不要补充学生没有表达过的理由、风险、优势、情绪或创意。
+不逐个学生罗列,不评价个人,不排名。
+如果提交内容包含“小组成员—负责帽子—贡献内容”等信息,只用于判断参与情况和思考分工,不对个人能力进行评价。
+如果不同已配置帽子的参与程度或内容丰富度存在明显差异,可以客观描述,但不要解释为学生“不会”某种思考。
+不要为了让分析看起来完整而强行生成结论;没有明显发现的内容可以省略。
+输出必须简洁,每个单元格尽量控制在 1–2 句话。
+请仅使用以下表格格式输出:
+思考帽
+参与情况
+班级 / 小组主要观点
+教师可关注
+⚪ 白帽|事实与信息
+X人,X% / X组,X%
+概括反复出现的事实、信息或信息缺口,最多2点
+如有事实混淆、证据不足或集中缺失的信息则指出,否则写“-”
+🔴 红帽|感受与直觉
+X人,X% / X组,X%
+概括主要感受、直觉或态度,最多2点
+如存在明显情绪分化或值得进一步了解的感受则指出,否则写“-”
+⚫ 黑帽|风险与问题
+X人,X% / X组,X%
+概括最集中的问题、风险或限制,最多2点
+值得后续讨论或验证的问题,最多1点
+🟡 黄帽|价值与机会
+X人,X% / X组,X%
+概括主要优势、价值或机会,最多2点
+如有值得进一步验证的价值判断则指出,否则写“-”
+🟢 绿帽|创意与可能性
+X人,X% / X组,X%
+概括主要创意、方案或不同可能性,最多2点
+值得继续展开或比较的想法,最多1点
+🔵 蓝帽|总结与推进
+X人,X% / X组,X%
+概括主要结论、共识或下一步行动,最多2点
+尚未解决、需要继续讨论的问题,最多1点
+注意:
+表格只保留“本次活动已配置 + 实际有有效提交”的思考帽。
+例如教师本次只配置白帽、黑帽、绿帽,则最终最多只输出这 3 行,不要出现红帽、黄帽、蓝帽。
+如果已配置的某顶帽子无人有效填写,则该行也删除。
+如果同一学生或小组提交了多个帽子,应分别计入对应帽子的参与统计。
+同一帽子下重复表达相同观点时,应合并统计和概括,不重复罗列。
+如果存在明显的多数观点与少数不同观点,可以表达为“多数小组认为……;另有少数组提出……”,不要逐组列举。
+对小组任务,不要因为某位成员负责某一顶帽子,就推断该成员个人更擅长这种思考方式。
+避免空泛表达,例如“学生思考比较全面”“大家讨论得很好”“学生参与积极”。
+尽量直接使用学生实际讨论中的主题、方案、问题、证据或观点名称。
+
+# 学生提交数据 #
+${chatMsg}`
+
+
+
+
   console.log('workUrl', props.workUrl)
   console.log('ai应用提示词', msg)
   if (!currentAnalysis.value) {

+ 3 - 1
src/views/Student/index.vue

@@ -3923,7 +3923,9 @@ const addOp3 = async (userTime: any, loadTime: any, object: any, status: any) =>
   }
   catch (e) {
     console.log(e)
-    return addOp3(userTime, loadTime, object, status)
+    setTimeout(() => {
+      addOp3(userTime, loadTime, object, status)
+    }, 10000)
   }
 
   const _time = new Date()

+ 3 - 1
src/views/Student/index2.vue

@@ -3291,7 +3291,9 @@ const addOp3 = async (userTime: any, loadTime: any, object: any, status: any) =>
   }
   catch (e) {
     console.log(e)
-    return addOp3(userTime, loadTime, object, status)
+    setTimeout(() => {
+      addOp3(userTime, loadTime, object, status)
+    }, 10000)
   }
 
   const _time = new Date()