Quellcode durchsuchen

优化管理端AI生成课校验逻辑和显示

liyanbo vor 1 Monat
Ursprung
Commit
c215942e75
2 geänderte Dateien mit 87 neuen und 51 gelöschten Zeilen
  1. 65 51
      src/views/bjdx/course/aiGenerate/aiGengrate.vue
  2. 22 0
      src/views/bjdx/coursetype/index.vue

+ 65 - 51
src/views/bjdx/course/aiGenerate/aiGengrate.vue

@@ -104,7 +104,7 @@
                     style="width: 300px"
                   >
                     <el-option label="课程通用" value=13 />
-                    <el-option label="诗词课" value=101 />
+                    <el-option label="诗词课" value=256 />
                   </el-select>
                 </div>
               </div>
@@ -558,7 +558,7 @@
                 重新生成
               </button>
 
-              <button class="primary-btn" :disabled="!canProceed" @click="nextStep">
+              <button class="primary-btn"  @click="nextStep">
                 预览完整脚本
               </button>
             </div>
@@ -568,16 +568,24 @@
           <div v-else-if="currentStep === 3" class="step-content">
             <div class="preview-container">
               <h3>课程脚本预览</h3>
-              <br />
+              
+              <div class="scrollable-content">
+                <br />
 
-              <div
-                class="validation-result"
-                :class="{ valid: isValidationPassed, invalid: !isValidationPassed }"
-              >
-                {{ validationMessage }}
-              </div>
+                <div v-if="isValidationPassed" class="validation-result valid">
+                  {{ validationMessage }}
+                </div>
+                <div v-else>
+                  <div 
+                    v-for="(error, index) in errorMessages" 
+                    :key="index" 
+                    class="validation-result invalid"
+                  >
+                    {{ error }}
+                  </div>
+                </div>
 
-              <div class="preview-content">
+                <div class="preview-content">
                 <div
                   v-for="(section, sectionIndex) in scriptData.sections"
                   :key="sectionIndex"
@@ -667,17 +675,18 @@
                     </div>
                   </div>
                 </div>
+                </div>
               </div>
 
               <div class="preview-actions">
                 <button class="secondary-btn" @click="currentStep = 2">返回修改</button>
-                <button
+<!--                <button
                   class="primary-btn"
                   :disabled="!isValidationPassed"
                   @click="showVideoPreview"
                 >
                   预览视频
-                </button>
+                </button>-->
                 <button class="primary-btn" :disabled="!isValidationPassed" @click="saveScript">
                   保存课程脚本
                 </button>
@@ -938,8 +947,7 @@ const canProceed = computed(() => {
               ((dialogue.type === 'digital' || dialogue.type === 'quest' || dialogue.type === 'poem') &&
                 dialogue.roleName &&
                 dialogue.content.trim() &&
-                dialogue.voiceoverUrl) ||
-              (dialogue.type === 'user' && dialogue.roleName && dialogue.content.trim())
+                dialogue.voiceoverUrl)
           )
       )
     default:
@@ -962,6 +970,7 @@ const isAnyVoiceoverGenerating = computed(() => {
 // 校验结果
 const isValidationPassed = ref(false)
 const validationMessage = ref('')
+const errorMessages = ref([])
 
 // 视频预览状态
 const showVideoPreviewModal = ref(false)
@@ -1415,7 +1424,7 @@ const generateAllVoiceovers = async () => {
       for (let j = 0; j < scriptData.sections[i].dialogues.length; j++) {
         const dialogue = scriptData.sections[i].dialogues[j]
         // 只处理没有语音URL的对话
-        if (!dialogue.voiceoverUrl) {
+        if (!dialogue.voiceoverUrl && dialogue.type !== 'poem') {
           await generateVoiceover(i, j)
         }
       }
@@ -1442,32 +1451,29 @@ const parseMarkdown = (text) => {
 // 步骤4:校验脚本
 const validateScript = () => {
   let isValid = true
-  let message = '校验通过'
-
-  if (!scriptData.sections.every((s) => s.name.trim())) {
-    isValid = false
-    message = '存在空的环节名称'
-  } else if (!scriptData.sections.every((s) => s.backgroundImage.url)) {
-    isValid = false
-    message = '存在未生成的背景图'
-  } else if (
-    !scriptData.sections.every((s) =>
-      s.dialogues.every(
-        (d) =>
-          ((d.type === 'digital' || d.type === 'quest' || d.type === 'poem') &&
-            d.roleName &&
-            d.content.trim() &&
-            d.voiceoverUrl) ||
-          (d.type === 'user' && d.roleName && d.content.trim())
-      )
-    )
-  ) {
-    isValid = false
-    message = '存在未完成的对话或语音'
-  }
+  errorMessages.value = []
+
+  // 检查环节名称、背景图
+  scriptData.sections.forEach((section, sectionIndex) => {
+    if (!section.name.trim() || !section.backgroundImage.url) {
+      errorMessages.value.push(`环节${sectionIndex + 1}:名称或背景图未配置!`)
+      isValid = false
+    }
+
+    // 检查对话
+    section.dialogues.forEach((dialogue, dialogueIndex) => {
+      // 只检查数字人、提问和诗词类型的对话
+      if (dialogue.type === 'digital' || dialogue.type === 'quest' || dialogue.type === 'poem') {
+        if (!dialogue.roleName || !dialogue.content.trim() || (dialogue.type !== 'poem' && !dialogue.voiceoverUrl)) {
+          errorMessages.value.push(`环节${sectionIndex + 1}:对话${dialogueIndex + 1}:存在完成内容!`)
+          isValid = false
+        }
+      }
+    })
+  })
 
   isValidationPassed.value = isValid
-  validationMessage.value = message
+  validationMessage.value = errorMessages.value.length > 0 ? '校验失败' : '校验通过'
 }
 
 // 步骤4:保存脚本
@@ -1486,12 +1492,10 @@ const saveScript = async () => {
 
 // 下一步操作
 const nextStep = () => {
-  if (canProceed.value) {
-    if (currentStep.value === 2) {
-      validateScript()
-    }
-    currentStep.value++
+  if (currentStep.value === 2) {
+    validateScript()
   }
+  currentStep.value++
 }
 
 // 显示视频预览
@@ -1751,6 +1755,12 @@ onUnmounted(() => {
   display: none;
 }
 
+/* 错误信息项样式 */
+.error-item {
+  margin-bottom: 8px;
+  line-height: 1.4;
+}
+
 .dialogue-type-tag.digital {
   background-color: #409eff;
 }
@@ -2642,32 +2652,36 @@ onUnmounted(() => {
   flex-direction: column;
 }
 
-.preview-content {
+.scrollable-content {
   flex: 1;
   overflow-y: auto;
-  margin-top: 20px;
-  margin-bottom: 30px;
+  margin-bottom: 20px;
   padding-right: 10px;
 }
 
-.preview-content::-webkit-scrollbar {
+.scrollable-content::-webkit-scrollbar {
   width: 6px;
 }
 
-.preview-content::-webkit-scrollbar-track {
+.scrollable-content::-webkit-scrollbar-track {
   background: #f1f1f1;
   border-radius: 3px;
 }
 
-.preview-content::-webkit-scrollbar-thumb {
+.scrollable-content::-webkit-scrollbar-thumb {
   background: #c1c1c1;
   border-radius: 3px;
 }
 
-.preview-content::-webkit-scrollbar-thumb:hover {
+.scrollable-content::-webkit-scrollbar-thumb:hover {
   background: #a1a1a1;
 }
 
+.preview-content {
+  margin-top: 20px;
+  margin-bottom: 30px;
+}
+
 .preview-actions {
   margin-top: auto;
   display: flex;

+ 22 - 0
src/views/bjdx/coursetype/index.vue

@@ -60,6 +60,9 @@
         <el-button type="danger" plain @click="toggleExpandAll">
           <Icon icon="ep:sort" class="mr-5px" /> 展开/折叠
         </el-button>
+<!--        <el-button type="primary" plain @click="openAiGenerate">-->
+<!--          <Icon icon="ep:magic-stick" class="mr-5px" /> AI生成-->
+<!--        </el-button>-->
       </el-form-item>
     </el-form>
   </ContentWrap>
@@ -134,6 +137,8 @@
 
   <!-- 表单弹窗:添加/修改 -->
   <CourseTypeForm ref="formRef" @success="getList" />
+  <!-- AI生成弹窗 -->
+  <AiGenerate ref="aiGenerateRef" :visible="aiGenerateVisible" @update:visible="(value) => aiGenerateVisible = value" @save="handleAiGenerateSave" />
 </template>
 
 <script setup lang="ts">
@@ -144,6 +149,7 @@ import CourseTypeForm from './CourseTypeForm.vue'
 import { ElButton } from 'element-plus'
 import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
 import { getTenantId } from '@/utils/auth'
+import AiGenerate from './aiGenerate/aiGenerate.vue'
 
 /** 课程-类型 列表 */
 defineOptions({ name: 'CourseType' })
@@ -161,6 +167,9 @@ const queryParams = reactive({
 })
 const queryFormRef = ref() // 搜索的表单
 const exportLoading = ref(false) // 导出的加载中
+// AI生成相关
+const aiGenerateVisible = ref(false)
+const aiGenerateRef = ref()
 
 /** 查询列表 */
 const getList = async () => {
@@ -229,6 +238,19 @@ const toggleExpandAll = async () => {
   refreshTable.value = true
 }
 
+/** 打开AI生成弹窗 */
+const openAiGenerate = () => {
+  aiGenerateVisible.value = true
+}
+
+/** 处理AI生成保存 */
+const handleAiGenerateSave = (scriptData, replacedUrls) => {
+  // 这里可以添加保存逻辑
+  console.log('AI生成保存', scriptData, replacedUrls)
+  // 保存成功后刷新列表
+  getList()
+}
+
 /** 初始化 **/
 onMounted(() => {
   getList()