Selaa lähdekoodia

AI古诗词按照需求新增5节小哥单独提示词
新增诗词背诵评价、仿写评价对话类型

liyanbo 2 kuukautta sitten
vanhempi
sitoutus
ae1ec3c5d6
2 muutettua tiedostoa jossa 356 lisäystä ja 18 poistoa
  1. 0 2
      src/types/auto-imports.d.ts
  2. 356 16
      src/views/bjdx/course/aiGenerate/aiGengrate.vue

+ 0 - 2
src/types/auto-imports.d.ts

@@ -7,8 +7,6 @@ export {}
 declare global {
   const DICT_TYPE: typeof import('@/utils/dict')['DICT_TYPE']
   const EffectScope: typeof import('vue')['EffectScope']
-  const ElMessage: typeof import('element-plus/es')['ElMessage']
-  const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
   const computed: typeof import('vue')['computed']
   const createApp: typeof import('vue')['createApp']
   const customRef: typeof import('vue')['customRef']

+ 356 - 16
src/views/bjdx/course/aiGenerate/aiGengrate.vue

@@ -105,6 +105,26 @@
                   >
                     <el-option label="课程通用" value="13" />
                     <el-option label="诗词课" value="256" />
+                    <el-option label="诗词课(英才小学生)" value="262" />
+                  </el-select>
+                </div>
+
+                <div v-if="selectedThemeType === '262'" class="selection-item">
+                  <label>课程小节</label>
+                  <el-select
+                    v-model="selectedLessonSection"
+                    size="large"
+                    placeholder="请选择课程小节"
+                    style="width: 300px"
+                  >
+                    <el-option
+                      v-for="section in poetryLessonSections"
+                      :key="section.value"
+                      :label="section.label"
+                      :value="section.value"
+                    >
+                      <span>({{ section.value }}){{ section.label }}</span>
+                    </el-option>
                   </el-select>
                 </div>
               </div>
@@ -311,7 +331,11 @@
                                   ? '诗词'
                                   : dialogue.type === 'poem_reading'
                                     ? '朗诵评价'
-                                    : '视频'
+                                    : dialogue.type === 'write_reading'
+                                      ? '写诗评价'
+                                      : dialogue.type === 'recite_reading'
+                                        ? '背诵诗词评价'
+                                        : '视频'
                         }}
                       </div>
                     </div>
@@ -707,7 +731,81 @@
                             <button
                               class="remove-btn"
                               @click="removeDialogue(sectionIndex, dialogueIndex)"
-                              >×</button
+                            >×</button
+                            >
+                          </div>
+                        </div>
+                      </template>
+
+                      <!-- 写诗评价 -->
+                      <template v-else-if="dialogue.type === 'write_reading'">
+                        <div class="dialogue-role-select">
+                          <el-select
+                            v-model="dialogue.roleName"
+                            placeholder="选择角色"
+                            style="width: 140px"
+                            clearable
+                          >
+                            <el-option
+                              v-for="role in digitalHumans"
+                              :key="role.id"
+                              :label="role.name"
+                              :value="role.name"
+                            />
+                          </el-select>
+                        </div>
+                        <div class="dialogue-content-container">
+                          <el-input
+                            v-model="dialogue.content"
+                            type="textarea"
+                            class="dialogue-content"
+                            placeholder="写诗评价内容..."
+                            :autosize="{ minRows: 2, maxRows: 4 }"
+                          />
+                        </div>
+                        <div class="action-buttons">
+                          <div class="action-buttons-row">
+                            <button
+                              class="remove-btn"
+                              @click="removeDialogue(sectionIndex, dialogueIndex)"
+                            >×</button
+                            >
+                          </div>
+                        </div>
+                      </template>
+
+                      <!-- 背诵诗词评价 -->
+                      <template v-else-if="dialogue.type === 'recite_reading'">
+                        <div class="dialogue-role-select">
+                          <el-select
+                            v-model="dialogue.roleName"
+                            placeholder="选择角色"
+                            style="width: 140px"
+                            clearable
+                          >
+                            <el-option
+                              v-for="role in digitalHumans"
+                              :key="role.id"
+                              :label="role.name"
+                              :value="role.name"
+                            />
+                          </el-select>
+                        </div>
+                        <div class="dialogue-content-container">
+                          <el-input
+                            v-model="dialogue.content"
+                            type="textarea"
+                            class="dialogue-content"
+                            placeholder="背诵诗词评价内容..."
+                            :autosize="{ minRows: 2, maxRows: 4 }"
+                          />
+                        </div>
+                        <div class="action-buttons">
+                          <div class="action-buttons-row">
+                            <button
+                              class="remove-btn"
+                              @click="removeDialogue(sectionIndex, dialogueIndex)"
+                            >×</button
                             >
                           </div>
                         </div>
@@ -726,18 +824,34 @@
                       >+ 添加提问与回复</button
                     >
 
-                    <button class="add-dialogue-btn poem" @click="addPoemDialogue(sectionIndex)"
-                      >+ 添加诗词</button
-                    >
-
                     <button class="add-dialogue-btn video" @click="addVideoDialogue(sectionIndex)"
                       >+ 添加视频</button
                     >
 
-                    <button class="add-dialogue-btn poem_reading" @click="addPoemReadingDialogue(sectionIndex)"
-                      >+ 添加朗诵评价</button
-                    >
-
+                    <div class="more-dropdown-wrapper">
+                      <button
+                        class="add-dialogue-btn more-btn"
+                        @click.stop="toggleMoreMenu(sectionIndex)"
+                      >+ 更多 ▾</button>
+                      <div
+                        v-if="activeMoreMenu === sectionIndex"
+                        class="more-dropdown-menu"
+                        @click.stop
+                      >
+                        <button class="more-item-btn poem" @click="addPoemDialogue(sectionIndex); activeMoreMenu = null"
+                          >+ 添加诗词</button
+                        >
+                        <button class="more-item-btn poem_reading" @click="addPoemReadingDialogue(sectionIndex); activeMoreMenu = null"
+                          >+ 添加朗诵评价</button
+                        >
+                        <button class="more-item-btn write_reading" @click="addWriteReadingDialogue(sectionIndex); activeMoreMenu = null"
+                          >+ 添加写诗评价</button
+                        >
+                        <button class="more-item-btn recite_reading" @click="addReciteReadingDialogue(sectionIndex); activeMoreMenu = null"
+                          >+ 添加背诵诗词评价</button
+                        >
+                      </div>
+                    </div>
                   </div>
                 </div>
               </div>
@@ -840,7 +954,11 @@
                                   ? '诗词'
                                   : dialogue.type === 'poem_reading'
                                     ? '朗诵评价'
-                                    : '视频'
+                                    : dialogue.type === 'write_reading'
+                                      ? '写诗评价'
+                                      : dialogue.type === 'recite_reading'
+                                        ? '背诵诗词评价'
+                                        : '视频'
                         }}
                               </div>
                               <div class="dialogue-role">
@@ -995,6 +1113,50 @@ const backgroundMusicTypes = ref([
   }
 ])
 
+// 诗词课(英才小学生)课程小节选项
+const poetryLessonSections = ref([
+  {
+    value: '1',
+    label: '读·共读辨情,初识诗境',
+    constraint: ['digital', 'poem_reading', 'poem'],
+    description: '引导学生朗读诗词,通过共读辨情,本节课只需要带着学生一起朗读,不需要其他对话类型。(对话类型参考:digital对话引导,poem诗句,poem_reading学生朗读,digital对话引导...)'
+  },
+  {
+    value: '2',
+    label: '悟·深究共情,解码精神',
+    constraint: ['digital', 'video', 'quest', 'user'],
+    description: '保证第一个环节的第一个对话类型是(video)AIGC视频类型,填充视频生成提示词(根据诗词情感生成提示词),' +
+      '后续再以作者和学生对话的方式进行沉浸式课堂教学,先逐句拆解每一首诗的含义,讲解重点字词。' +
+      '然后展开讲解诗人的生平背景,' +
+      '最后讲解整句诗的思想,中间穿插互动提问(问题方向为:抓住诗词特色画面,理解环境描写如何烘托人物心境,情感这几点来提问)'
+  },
+  {
+    value: '3',
+    label: '用·印证文脉,联结现实',
+    constraint: ['digital', 'poem', 'recite_reading'],
+    description: '本节小课是先跟着诗词跟读,都读完后给出引导进行背诵,注意:逐句背诵,每一句诗词引导背诵和用户背诵都要单独一个环节,方便环节背景图应景(背景图上不要出现诗词语句)' +
+      '注意对话流程:digital对话引导跟读,poem诗句,digital对话背诵引导(不要出现诗词语句),recite_reading学生背诵...'
+  },
+  {
+    value: '4',
+    label: '创·汲智明志,创意表达',
+    constraint: ['digital', 'quest', 'user', 'write_reading'],
+    description: '将诗词内容,结合新的时代进行思考,给同学们进行提问,引出创作动机,并引导学生根据其中经典诗句进行仿写,可以先给出例子,然后引导学生进行仿写。' +
+      '注意每条仿写对话前面都要有引导对话和示例,引导学生根据示例进行仿写。' +
+      '仿写结束后以作者和学生对话的方式进行沉浸式课堂教学,中间穿插互动提问'
+  },
+  {
+    value: '5',
+    label: '评价',
+    constraint: ['digital', 'poem', 'poem_reading', 'write_reading'],
+    description: '本节课需要先进行诗词朗读,引导学生根据诗词内容进行评价(注意对话流程:digital对话引导,poem诗句,poem_reading学生朗读...)' +
+      '然后引导学生仿写诗词进行评价。(后续对话流程:digital对话引导先给出示例,write_reading学生仿写)'
+  }
+])
+
+// 当前选中的课程小节
+const selectedLessonSection = ref('')
+
 // 从localStorage加载脚本数据
 const loadScriptDataFromCache = () => {
   try {
@@ -1292,10 +1454,16 @@ const canProceed = computed(() => {
             (dialogue) =>
               (dialogue.type === 'digital' ||
                 dialogue.type === 'quest' ||
-                dialogue.type === 'poem') &&
+                dialogue.type === 'poem' ||
+                dialogue.type === 'poem_reading' ||
+                dialogue.type === 'write_reading' ||
+                dialogue.type === 'recite_reading') &&
               dialogue.roleName &&
               dialogue.content.trim() &&
-              dialogue.voiceoverUrl
+              (dialogue.type === 'poem_reading' ||
+                dialogue.type === 'write_reading' ||
+                dialogue.type === 'recite_reading' ||
+                dialogue.voiceoverUrl)
           )
       )
     default:
@@ -1376,6 +1544,23 @@ const generateScript = async () => {
     })
     content += zhujiang.join(',') + ')'
 
+    // 如果选择了诗词课(英才小学生)并且选中了课程小节,将其信息追加到内容中
+    if (selectedThemeType.value === '262' && selectedLessonSection.value) {
+      const lessonSection = poetryLessonSections.value.find(
+        (s) => s.value === selectedLessonSection.value
+      )
+      if (lessonSection) {
+        content +=
+          '【课程小节:' +
+          lessonSection.label +
+          ';本节课只能出现下面的对话类型:' +
+          lessonSection.constraint.join(',') +
+          '禁止出现对话类型之外的对话类型;小节描述:' +
+          lessonSection.description +
+          '】'
+      }
+    }
+
     await createAiRoleIdConversation(Number(selectedThemeType.value))
     currentStep.value = 2
     await doSendMessageStream(activeConversationId.value, content)
@@ -1630,6 +1815,35 @@ const addPoemReadingDialogue = (sectionIndex) => {
   })
 }
 
+// 步骤2:添加写诗评价
+const addWriteReadingDialogue = (sectionIndex) => {
+  scriptData.sections[sectionIndex].dialogues.push({
+    type: 'write_reading',
+    content: '',
+    roleName: '',
+  })
+}
+
+// 步骤2:添加背诵诗词评价
+const addReciteReadingDialogue = (sectionIndex) => {
+  scriptData.sections[sectionIndex].dialogues.push({
+    type: 'recite_reading',
+    content: '',
+    roleName: '',
+  })
+}
+
+// 步骤2:切换更多按钮菜单
+const activeMoreMenu = ref(null)
+const toggleMoreMenu = (sectionIndex) => {
+  activeMoreMenu.value = activeMoreMenu.value === sectionIndex ? null : sectionIndex
+}
+
+// 点击其他区域关闭更多菜单
+const closeMoreMenu = () => {
+  activeMoreMenu.value = null
+}
+
 // 步骤2:添加提问与用户回复
 const addQuestWithUserReply = (sectionIndex) => {
   // 添加提问类型对话
@@ -2133,12 +2347,12 @@ const validateScript = () => {
 
     // 检查对话
     section.dialogues.forEach((dialogue, dialogueIndex) => {
-      // 检查数字人、提问、诗词和朗诵评价类型的对话
-      if (dialogue.type === 'digital' || dialogue.type === 'quest' || dialogue.type === 'poem' || dialogue.type === 'poem_reading') {
+      // 检查数字人、提问、诗词、朗诵评价、写诗评价、背诵诗词评价类型的对话
+      if (dialogue.type === 'digital' || dialogue.type === 'quest' || dialogue.type === 'poem' || dialogue.type === 'poem_reading' || dialogue.type === 'write_reading' || dialogue.type === 'recite_reading') {
         if (
           !dialogue.roleName ||
           !dialogue.content.trim() ||
-          (dialogue.type !== 'poem' && dialogue.type !== 'poem_reading' && !dialogue.voiceoverUrl)
+          (dialogue.type !== 'poem' && dialogue.type !== 'poem_reading' && dialogue.type !== 'write_reading' && dialogue.type !== 'recite_reading' && !dialogue.voiceoverUrl)
         ) {
           errorMessages.value.push(
             `环节${sectionIndex + 1}:对话${dialogueIndex + 1}:存在完成内容!`
@@ -2238,6 +2452,9 @@ onMounted(async () => {
   // 设置初始步骤
   currentStep.value = props.initialStep
 
+  // 监听文档点击关闭更多菜单
+  document.addEventListener('click', closeMoreMenu)
+
   try {
     const params = {
       pageOn: 1,
@@ -2283,6 +2500,7 @@ onUnmounted(() => {
   if (inProgressVideoTimer.value) {
     clearInterval(inProgressVideoTimer.value)
   }
+  document.removeEventListener('click', closeMoreMenu)
 })
 </script>
 
@@ -2577,6 +2795,14 @@ onUnmounted(() => {
   background-color: #7d60a4;
 }
 
+.dialogue-type-tag.write_reading {
+  background-color: #c23a70;
+}
+
+.dialogue-type-tag.recite_reading {
+  background-color: #2aa898;
+}
+
 .dialogue-type-tag.video {
   background-color: #8b4513;
 }
@@ -2616,6 +2842,14 @@ onUnmounted(() => {
   border-left: 4px solid #7d60a4;
 }
 
+.dialogue-item.write_reading {
+  border-left: 4px solid #c23a70;
+}
+
+.dialogue-item.recite_reading {
+  border-left: 4px solid #2aa898;
+}
+
 /* 对话头部 */
 .dialogue-header {
   margin-bottom: 10px;
@@ -2698,11 +2932,26 @@ onUnmounted(() => {
   color: white;
 }
 
+.add-dialogue-btn.write_reading {
+  background-color: #c23a70;
+  color: white;
+}
+
+.add-dialogue-btn.recite_reading {
+  background-color: #2aa898;
+  color: white;
+}
+
 .add-dialogue-btn.quest-user {
   background-color: #e6a23c;
   color: white;
 }
 
+.add-dialogue-btn.more-btn {
+  background-color: #4a5568;
+  color: white;
+}
+
 .add-dialogue-btn.user:hover {
   background-color: #67c23a;
   border-color: #67c23a;
@@ -2726,6 +2975,97 @@ onUnmounted(() => {
   border-color: #73767a;
 }
 
+.add-dialogue-btn.poem_reading:hover {
+  background-color: #624a83;
+  border-color: #624a83;
+  color: white;
+}
+
+.add-dialogue-btn.write_reading:hover {
+  background-color: #9e2a56;
+  border-color: #9e2a56;
+  color: white;
+}
+
+.add-dialogue-btn.recite_reading:hover {
+  background-color: #208174;
+  border-color: #208174;
+  color: white;
+}
+
+.add-dialogue-btn.more-btn:hover {
+  background-color: #2d3748;
+  border-color: #2d3748;
+  color: white;
+}
+
+/* 更多下拉菜单容器 */
+.more-dropdown-wrapper {
+  position: relative;
+  display: inline-block;
+}
+
+/* 更多下拉菜单 */
+.more-dropdown-menu {
+  position: absolute;
+  top: 100%;
+  right: 0;
+  margin-top: 5px;
+  background-color: white;
+  border: 1px solid #d9d9d9;
+  border-radius: 6px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+  padding: 6px;
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+  min-width: 170px;
+  z-index: 100;
+}
+
+/* 下拉菜单中按钮 */
+.more-item-btn {
+  padding: 8px 12px;
+  border: none;
+  border-radius: 4px;
+  font-size: 14px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  gap: 5px;
+  text-align: left;
+  width: 100%;
+  color: white;
+}
+
+.more-item-btn.poem {
+  background-color: #909399;
+}
+.more-item-btn.poem:hover {
+  background-color: #73767a;
+}
+.more-item-btn.poem_reading {
+  background-color: #7d60a4;
+}
+.more-item-btn.poem_reading:hover {
+  background-color: #624a83;
+}
+.more-item-btn.write_reading {
+  background-color: #c23a70;
+}
+.more-item-btn.write_reading:hover {
+  background-color: #9e2a56;
+}
+.more-item-btn.recite_reading {
+  background-color: #2aa898;
+}
+.more-item-btn.recite_reading:hover {
+  background-color: #208174;
+}
+
 /* 上传相关样式 */
 .upload-container {
   margin-top: 10px;