Flex
2025-06-05 43f95dc1acae0b23febd0d602fbccbf9762c30f3
easegen-front/src/views/chooseTemplate/index.vue
@@ -33,15 +33,15 @@
        <span v-if="saveTime">{{ saveTime }} {{ t('courseCenter.saved') }}</span>
        <el-button size="small" @click="saveSubmit('save')">{{ t('common.save') }}</el-button>
        <el-button type="primary" size="small" @click="saveSubmit('')">{{
            t('courseCenter.composeViode')
          }}</el-button>
          t('courseCenter.composeViode')
        }}</el-button>
      </div>
    </div>
    <div class="template-main">
      <div class="template-box template-left">
        <div class="page">
          <div
          >{{ t('courseCenter.page') }}:({{ PPTArr ? PPTArr.length : 1 }}){{
            >{{ t('courseCenter.page') }}:({{ PPTArr ? PPTArr.length : 1 }}){{
              t('courseCenter.pageTitle')
            }}</div
          >
@@ -174,18 +174,21 @@
          <div class="list">
            <div
              class="main-image-box"
              :style="{ width: viewSize.width + 'px', height: viewSize.height + 'px',position: 'relative' }"
              :style="{
                width: viewSize.width + 'px',
                height: viewSize.height + 'px',
                position: 'relative'
              }"
            >
              <!-- 背景(必显示) -->
              <el-image
                v-show="selectPPT.pictureUrl && selectPPT.digitalHuman.show==false"
                v-show="selectPPT.pictureUrl && selectPPT.digitalHuman.show == false"
                class="background1"
                :src="selectPPT.pictureUrl"
                style="z-index: 2"
              />
              <el-image
                v-show="selectPPT.pictureUrl && selectPPT.digitalHuman.show==true"
                v-show="selectPPT.pictureUrl && selectPPT.digitalHuman.show == true"
                class="background1"
                :src="selectPPT.pictureUrl"
                style="z-index: 1"
@@ -214,7 +217,7 @@
                @resize-end="print('PPT resize-end')"
                style="z-index: 3"
              >
                <el-image class="ppt-bg" :src="selectPPT.innerPicture.src"  />
                <el-image class="ppt-bg" :src="selectPPT.innerPicture.src" />
                <el-icon
                  v-if="selectPPT.innerPicture.active"
                  size="20"
@@ -227,7 +230,7 @@
              </Vue3DraggableResizable>
              <!-- 数字人 -->
              <Vue3DraggableResizable
                v-if="selectPPT.digitalHuman.show==true && selectPPT.digitalHuman?.host"
                v-if="selectPPT.digitalHuman.show == true && selectPPT.digitalHuman?.host"
                :parent="false"
                :lockAspectRatio="true"
                :minW="350"
@@ -266,7 +269,7 @@
                </el-icon>
              </Vue3DraggableResizable>
              <Vue3DraggableResizable
                v-if="selectPPT.digitalHuman.show==false && selectPPT.digitalHuman?.host"
                v-if="selectPPT.digitalHuman.show == false && selectPPT.digitalHuman?.host"
                :parent="false"
                :lockAspectRatio="true"
                :minW="350"
@@ -360,12 +363,12 @@
        </div>
        <div class="voice-main">
          <el-text class="mx-1" type="primary" size="small">{{
              t('courseCenter.oralBroadcastingContent')
            }}</el-text>
            t('courseCenter.oralBroadcastingContent')
          }}</el-text>
          <div class="media-box">
            <el-button type="primary" :icon="Mic" size="small" @click="openSelect">{{
                selectPPT.selectAudio ? selectPPT.selectAudio.name : t('courseCenter.notSelect')
              }}</el-button>
              selectPPT.selectAudio ? selectPPT.selectAudio.name : t('courseCenter.notSelect')
            }}</el-button>
            <el-button
              type="success"
              :icon="Headset"
@@ -376,15 +379,21 @@
        </div>
        <div v-if="selectPPT.driverType == 1" style="position: relative">
          <div class="middle-textarea">
            <Editor style="height: 196px; overflow-y: hidden;" v-model="selectPPT.pptRemark" :defaultConfig="editorConfig" mode="simple" @on-created="handleCreated" />
            <Editor
              style="height: 196px; overflow-y: hidden"
              v-model="selectPPT.pptRemark"
              :defaultConfig="editorConfig"
              mode="simple"
              @on-created="handleCreated"
            />
          </div>
          <div class="tool-box">
            <div class="tool-btn">
              <div></div>
            </div>
            <el-button type="primary" :icon="VideoPlay" size="small" @click="createAudio">{{
                t('courseCenter.tryListening')
              }}</el-button>
              t('courseCenter.tryListening')
            }}</el-button>
          </div>
          <div class="audio-play" v-if="showAudioPlay">
            <div>{{ t('courseCenter.listeningTrial') }}...</div>
@@ -416,13 +425,14 @@
            >
              <template #trigger>
                <el-button type="primary" :icon="Upload">{{
                    t('courseCenter.uploadAudio')
                  }}</el-button>
                  t('courseCenter.uploadAudio')
                }}</el-button>
              </template>
            </el-upload>
          </el-tooltip>
        </div>
      </div>
      <!-- 数字人 -->
      <div class="template-box template-right" v-if="showDigitalHumanTool">
        <div class="tabs-1">
          <div
@@ -474,7 +484,7 @@
              }"
            />
          </div>
          <el-empty v-if="hostList.length==0" description="暂无数据" />
          <el-empty v-if="hostList.length == 0" description="暂无数据" />
          <Pagination
            small="true"
            :total="total"
@@ -504,9 +514,9 @@
            v-for="(template, index) in templates"
            :key="index"
            :style="{
                width: '90%',
                maxWidth: '90%',
              }"
              width: '90%',
              maxWidth: '90%'
            }"
            @click="handleTemplateSelection(template)"
          >
            <div class="list-index" :style="template.isActive ? 'background: #409eff' : ''">
@@ -514,11 +524,95 @@
            </div>
            <el-image class="background" :src="template.previewImage" fit="contain" />
          </div>
          <el-empty v-if="templates.length==0" description="暂无数据" />
          <el-empty v-if="templates.length == 0" description="暂无数据" />
        </div>
<!--        <div class="apply-all">-->
<!--          <el-checkbox v-model="applyAllTemplate" :label="t('courseCenter.uploadAudio')" />-->
<!--        </div>-->
        <!--        <div class="apply-all">-->
        <!--          <el-checkbox v-model="applyAllTemplate" :label="t('courseCenter.uploadAudio')" />-->
        <!--        </div>-->
      </div>
      <!-- 声音 -->
      <div class="template-box template-right" v-if="SoundTool">
        <div class="SoundArea">
          <div class="SoundClassArea">
            <!-- 语种 -->
            <div>
              <el-select
                v-model="selectLanguage.value"
                placeholder="请选择语种"
                @change="LanguageChange"
              >
                <el-option
                  v-for="item in languageList"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                />
              </el-select>
            </div>
            <!-- 性别 -->
            <div>
              <el-select v-model="changeAudio" placeholder="请选择性别" @change="AudioChange()">
                <el-option
                  v-for="item in audioType"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                />
              </el-select>
            </div>
            <!-- 类型 -->
            <div>
              <el-select
                v-model="ChangeSoundTypeList.value"
                placeholder="请选择声音类型"
                @change="SoundTypeChange"
              >
                <el-option
                  v-for="item in SoundTypeList"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                />
              </el-select>
            </div>
          </div>
          <div class="SoundModelArea" v-loading="soundLoading">
            <div
              class="ModealBox"
              v-for="(item, index) in audioList"
              :key="index"
              @click="handleSelect(item)"
              @mouseenter="handleMouseenter(item)"
              @mouseleave="handleMouseleave(item)"
              :class="item.isSelect ? 'slectModel' : ''"
            >
              <div class="ImgBox">
                <img :src="item.avatarUrl" alt="" />
              </div>
              <div class="TextArea">
                <p> {{ item.name }} </p>
                <p> {{ item.introduction }} </p>
              </div>
              <img
                class="play-img"
                v-if="item.isHover && !item.isPlay"
                src="@/assets/imgs/play.png"
                alt=""
                @click.stop="playAudio(item)"
              />
              <img
                class="play-img"
                v-if="item.isHover && item.isPlay"
                src="@/assets/imgs/pause.png"
                alt=""
                @click.stop="SoundpauseAudio(item)"
              />
            </div>
          </div>
          <div class="ButtonArea">
            <el-button type="primary" @click="submitForm">{{ t('common.ok') }}</el-button>
          </div>
        </div>
      </div>
      <!-- 背景设置 -->
      <div class="template-box template-right" v-if="showHeadImageTool">
@@ -553,20 +647,32 @@
    <mergeWarningDialog ref="warningDialog" />
    <ReplaceDialog ref="replaceDialog" :ppt-arr="PPTArr" @submit="handleReplacement" />
    <!-- 多音字 -->
    <el-dialog v-model="dialogVisible" title="点击需要纠正的多音字,选择正确的发音" width="500" @close="dialogVisible = false">
      <el-tag v-for="(item, index) in textList" :key="index" type="primary" effect="dark" style="margin-right: 10px;cursor: pointer;" @click="handleTag(item)">
    <el-dialog
      v-model="dialogVisible"
      title="点击需要纠正的多音字,选择正确的发音"
      width="500"
      @close="dialogVisible = false"
    >
      <el-tag
        v-for="(item, index) in textList"
        :key="index"
        type="primary"
        effect="dark"
        style="margin-right: 10px; cursor: pointer"
        @click="handleTag(item)"
      >
        {{ item }}
      </el-tag>
    </el-dialog>
    <el-dialog v-model="dialogVisible1" title="提示" width="500px" style="height: 150px">
      <p style="margin-bottom: 20px;font-size: 18px">是否要将此模板应用到所有页面</p>
      <p style="margin-bottom: 20px; font-size: 18px">是否要将此模板应用到所有页面</p>
      <span class="dialog-footer">
        <el-button @click="handleTemplateSelection1(1)">应用当前页</el-button>
        <el-button type="primary" @click="handleTemplateSelection1(2)">应用所有页</el-button>
      </span>
    </el-dialog>
    <el-dialog v-model="dialogVisible2" title="提示" width="500px" style="height: 150px">
      <p style="margin-bottom: 20px;font-size: 18px">是否要将此数字人应用到所有页面</p>
      <p style="margin-bottom: 20px; font-size: 18px">是否要将此数字人应用到所有页面</p>
      <span class="dialog-footer">
        <el-button @click="chooseHost1(1)">应用当前页</el-button>
        <el-button type="primary" @click="chooseHost1(2)">应用所有页</el-button>
@@ -594,6 +700,8 @@
import templateActive from '@/assets/imgs/template-active.png'
import user from '@/assets/imgs/user.png'
import userActive from '@/assets/imgs/user-active.png'
import sound from '@/assets/imgs/sound.png'
import soundActive from '@/assets/imgs/sound-active.png'
import bg from '@/assets/imgs/bg.png'
import bgActive from '@/assets/imgs/bg-active.png'
import innerPicture from '@/assets/imgs/inner-picture.png'
@@ -622,6 +730,8 @@
import { polyphonic } from 'pinyin-pro'
import { useEditorHtml } from '@/hooks/web/useEditorHtml'
import { ElMessage, ElMessageBox } from 'element-plus'
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
import { measureMemory } from 'vm'
const editorHtml = useEditorHtml()
const router = useRouter()
@@ -629,8 +739,8 @@
const userStore = useUserStore()
const userId = computed(() => userStore.user.id)
const message = useMessage()
const dialogVisible1=ref(false)
const dialogVisible2=ref(false)
const dialogVisible1 = ref(false)
const dialogVisible2 = ref(false)
const isEditing = ref(false)
const inputRef = ref(null)
const editName = ref('')
@@ -647,17 +757,17 @@
    inputRef.value.focus()
  })
}
const hostValue=ref({})
const hostValue = ref({})
const chooseHost = (item) => {
  dialogVisible2.value = true
  hostValue.value = item
}
const chooseHost1 = (index) => {
  if (index==1){
  if (index == 1) {
    applyAllHost.value = false
    applyHostToPages(hostValue.value)
    dialogVisible2.value = false
  }else if(index==2){
  } else if (index == 2) {
    applyAllHost.value = true
    applyHostToPages(hostValue.value)
    dialogVisible2.value = false
@@ -670,7 +780,7 @@
  const pagesToUpdate = applyAllHost.value ? PPTArr.value : [selectPPT.value]
  pagesToUpdate.forEach(page => {
  pagesToUpdate.forEach((page) => {
    page.digitalHuman.host = host
    initHumanPositon(host, page.digitalHuman)
  })
@@ -785,7 +895,7 @@
}
const tabs4Click = (item) => {
  tabs4ActiveNum.value = item.itemValue
  queryParams1.zg=tabs4ActiveNum.value
  queryParams1.zg = tabs4ActiveNum.value
  getList1()
}
@@ -812,6 +922,13 @@
    activeUrl: userActive,
    isActive: false
  },
  // 声音类型
  {
    name: t('courseCenter.sound'),
    url: sound,
    activeUrl: soundActive,
    isActive: false
  }
  // {
  //   name: t('courseCenter.background'),
  //   url: bg,
@@ -828,26 +945,28 @@
const showHeadImageTool = ref(false)
const showDigitalHumanTool = ref(false)
// 声音
const SoundTool = ref(false)
const showTemplateTool = ref(false)
const showInnerPictureTool = ref(false)
const applyAllTemplate = ref(false)
const templateSelection=ref({})
const templateSelection = ref({})
const handleTemplateSelection = (template) => {
  console.log(template)
  dialogVisible1.value=true
  templateSelection.value=template
  dialogVisible1.value = true
  templateSelection.value = template
  console.log(templateSelection.value)
}
const handleTemplateSelection1 = (index) => {
  if (index==2){
  if (index == 2) {
    applyAllTemplate.value = true
    chooseTemplate(templateSelection.value)
    dialogVisible1.value=false
  }else if(index==1){
    dialogVisible1.value = false
  } else if (index == 1) {
    applyAllTemplate.value = false
    chooseTemplate(templateSelection.value)
    dialogVisible1.value=false
    dialogVisible1.value = false
  }
}
const handleChangeTool = (item) => {
@@ -861,15 +980,239 @@
  if (item.name == t('courseCenter.digitalPeople')) {
    tabs1ActiveNum.value = '0'
    getList()
  }else if (item.name == t('courseCenter.template')) {
  } else if (item.name == t('courseCenter.template')) {
    tabs4ActiveNum.value = '2'
    queryParams1.zg=tabs4ActiveNum.value
    queryParams1.zg = tabs4ActiveNum.value
    getList1()
  } else if (item.name == t('courseCenter.sound')) {
    // 声音的处理       selectAudio
    // 获取语言种类
    getLanguageList()
    //获取性别种类
    getAudioType()
    // 获取声音类别
    getVoiceType()
    // 获取模型列表
    getSoundModelList()
    // 获取可选的声音类型列表
    GetSoundTypeList()
  }
  showHeadImageTool.value = item.name === t('courseCenter.background')
  showTemplateTool.value = item.name === t('courseCenter.template')
  showDigitalHumanTool.value = item.name === t('courseCenter.digitalPeople')
  SoundTool.value = item.name === t('courseCenter.sound')
  showInnerPictureTool.value = item.name === t('courseCenter.pictureInPicture')
}
// 当前选择的语种
const selectLanguage = ref<any>()
// 可选的语种列表
const languageList = ref()
// 获取语言字典
const getLanguageList = () => {
  let res = getStrDictOptions(DICT_TYPE.DIGITALCOURSE_VOICES_LANGUAGE)
  languageList.value = res
  selectLanguage.value = { ...languageList.value[0] }
}
// 可选的性别列表
const audioType = ref()
// 当前选择的性别
const changeAudio = ref<any>({ value: '' })
//获取性别字典
const getAudioType = () => {
  const list = getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)
  audioType.value = list
  changeAudio.value = list[0].value
}
// 可选的声音类别列表
const SoundTypeList = ref()
// 当前选择的声音类别
const ChangeSoundTypeList = ref()
// 获取可选的声音类型列表
const GetSoundTypeList = () => {
  const res = getIntDictOptions(DICT_TYPE.DIGITALCOURSE_VOICES_TYPE)
  SoundTypeList.value = res
  ChangeSoundTypeList.value = { ...res[0] }
}
//可选的声音模型的声音类别列表
const SoundvoiceTypeList = ref()
// 当前选择的声音模型的声音类别
const activeSoundType = ref<any>({ value: '' })
//获取的声音模型的声音类别
const getVoiceType = () => {
  const list1 = getIntDictOptions(DICT_TYPE.DIGITALCOURSE_VOICES_TYPE)
  SoundvoiceTypeList.value = list1
  activeSoundType.value = { ...list1[0] }
}
// 获取声音模型列表请求参数
const soundQueryParams = reactive({
  pageNo: 1,
  pageSize: 32,
  language: '',
  gender: '',
  voiceType: '',
  status: 0 // 状态:0正常,1异常
})
// 可选择的声音模型列表
const audioList = ref()
// 是否正在加载模型列表
const soundLoading = ref(false)
// 获取声音模型列表
const getSoundModelList = async () => {
  try {
    soundLoading.value = true
    // 语言类型
    soundQueryParams.language = selectLanguage?.value.value ?? ''
    // 性别
    soundQueryParams.gender = changeAudio?.value ?? ''
    // 声音类型
    soundQueryParams.voiceType = activeSoundType?.value.value ?? ''
    const data = await pptTemplateApi.videlPageList(soundQueryParams)
    data.list.forEach((item) => {
      item.isHover = false
      item.isPlay = false
      item.isSelect = false
    })
    audioList.value = data.list
    total.value = data.total
  } finally {
    soundLoading.value = false
  }
}
// 语种选择
const LanguageChange = (event) => {
  languageList.value.forEach((element) => {
    if (element.value === event) {
      selectLanguage.value = { ...element }
    }
  })
  getSoundModelList()
}
// 性别选择
const AudioChange = () => {
  getSoundModelList()
}
// 类别选择
const SoundTypeChange = (event) => {
  SoundTypeList.value.forEach((element) => {
    if (element.value === event) {
      ChangeSoundTypeList.value = { ...element }
    }
  })
  getSoundModelList()
}
//选择声音模型
const selectList = ref()
const handleSelect = (item) => {
  selectList.value = [item]
  audioList.value.forEach((child) => {
    if (child.id == item.id) {
      child.isSelect = true
    } else {
      child.isSelect = false
    }
  })
}
// 确定按钮点击处理函数
const submitForm = () => {
  if (ChangeSoundTypeList.value.value === 2) {
    //此时为通用
    if (activeSoundType.value === 1 && selectList.value.length === 0) {
      message.warning('请选择声音模型')
      return false
    }
    selectAudio(selectList.value)
  } else if (ChangeSoundTypeList.value.value === 1) {
    // 清除选中的音频
    selectList.value = null
    // 清除列表中所有选中状态
    if (audioList.value) {
      audioList.value.forEach((item) => {
        item.isSelect = false
      })
    }
    // 停止当前播放的音频
    if (SoundcurrentAudio.value) {
      SoundcurrentAudio.value.pause()
      SoundcurrentAudio.value = null
    }
    // 重置当前播放状态
    if (SoundcurrentlyPlaying.value) {
      SoundcurrentlyPlaying.value.isPlay = false
      SoundcurrentlyPlaying.value = null
    }
    selectAudio(undefined)
  }
}
// 鼠标移入与移出
const handleMouseenter = (item) => {
  audioList.value.forEach((child) => {
    if (child.id == item.id) {
      child.isHover = true
    }
  })
}
const handleMouseleave = (item) => {
  audioList.value.forEach((child) => {
    if (child.id == item.id) {
      child.isHover = false
    }
  })
}
// 音频管理
const SoundcurrentAudio = ref<HTMLAudioElement | null>(null)
const SoundcurrentlyPlaying = ref<any>(null)
const playAudio = async (item: any) => {
  // 如果点击的是当前正在播放的项目,则暂停
  if (SoundcurrentlyPlaying.value && SoundcurrentlyPlaying.value.id === item.id) {
    SoundpauseAudio(item)
    return
  }
  // 停止当前播放的音频
  if (SoundcurrentAudio.value) {
    SoundcurrentAudio.value.pause()
    SoundcurrentAudio.value = null
  }
  // 如果之前有播放的项目,重置其状态
  if (SoundcurrentlyPlaying.value) {
    SoundcurrentlyPlaying.value.isPlay = false
  }
  // 设置新的播放项目
  SoundcurrentlyPlaying.value = item
  item.isPlay = true
  // 创建新的音频对象并播放
  SoundcurrentAudio.value = new Audio(item.auditionUrl)
  SoundcurrentAudio.value.play()
  // 添加播放结束事件监听
  SoundcurrentAudio.value.addEventListener('ended', () => {
    item.isPlay = false
    SoundcurrentlyPlaying.value = null
    SoundcurrentAudio.value = null
  })
}
const SoundpauseAudio = (item: any) => {
  if (
    SoundcurrentAudio.value &&
    SoundcurrentlyPlaying.value &&
    SoundcurrentlyPlaying.value.id === item.id
  ) {
    SoundcurrentAudio.value.pause()
    item.isPlay = false
    SoundcurrentlyPlaying.value = null
  }
}
const PPTArr = ref([])
@@ -979,13 +1322,13 @@
  return selectPPT.value?.pictureUrl || ''
})
//ppt人脸校验方法
const PPtIsHaveFace = async ()=>{
const PPtIsHaveFace = async () => {
  IsEndCheckFace.value = false
  //添加ppt中人脸校验
  //向原始ppt添加数据,用作后续ppt中是否包含人脸的数据校验原始数据
  const InitPpt = PPTArr.value.map( (item)=>{
      return item.innerPicture.src
  } )
  const InitPpt = PPTArr.value.map((item) => {
    return item.innerPicture.src
  })
  const { detectFacesInImages } = useFaceDetection()
  IsHaveFace.value = await detectFacesInImages(InitPpt)
  IsEndCheckFace.value = true
@@ -1154,47 +1497,44 @@
}
const copyDocument = (item, index) => {
  ElMessageBox.confirm(
    '是否复制该页面?',
    '提示',
    {
      confirmButtonText: '是',
      cancelButtonText: '否',
      type: 'warning',
    }).then(() => {
    let copyItem = cloneDeep(item)
    copyItem.id = generateUUID()
    copyItem.isActive = false
    // 深拷贝数字人配置
    copyItem.digitalHuman = {...item.digitalHuman}
    PPTArr.value.splice(index + 1, 0, copyItem)
  }).catch(() => {
    ElMessage({
      type: 'info',
      message: '已取消复制',
    })
  ElMessageBox.confirm('是否复制该页面?', '提示', {
    confirmButtonText: '是',
    cancelButtonText: '否',
    type: 'warning'
  })
    .then(() => {
      let copyItem = cloneDeep(item)
      copyItem.id = generateUUID()
      copyItem.isActive = false
      // 深拷贝数字人配置
      copyItem.digitalHuman = { ...item.digitalHuman }
      PPTArr.value.splice(index + 1, 0, copyItem)
    })
    .catch(() => {
      ElMessage({
        type: 'info',
        message: '已取消复制'
      })
    })
}
const deleteDocument = (item) => {
  ElMessageBox.confirm(
    '是否删除该页面?',
    '提示',
    {
      confirmButtonText: '是',
      cancelButtonText: '否',
      type: 'warning',
    }
  ).then(() => {
    PPTArr.value = PPTArr.value.filter((child) => child.id !== item.id)
    //已经进行过删除操作
    DeleteD.value = true
  }).catch(() => {
    ElMessage({
      type: 'info',
      message: '已取消删除',
    })
  ElMessageBox.confirm('是否删除该页面?', '提示', {
    confirmButtonText: '是',
    cancelButtonText: '否',
    type: 'warning'
  })
    .then(() => {
      PPTArr.value = PPTArr.value.filter((child) => child.id !== item.id)
      //已经进行过删除操作
      DeleteD.value = true
    })
    .catch(() => {
      ElMessage({
        type: 'info',
        message: '已取消删除'
      })
    })
}
const deleteDigitalHuman = () => {
@@ -1227,7 +1567,7 @@
const queryParams1 = reactive({
  pageNo: 1,
  pageSize: 100,
  zg:''
  zg: ''
})
const selectHost = ref(null)
@@ -1295,6 +1635,7 @@
}
const selectAudio = (data) => {
  console.log(data)
  audioSelectData.value = data
  if (data == undefined) {
    selectPPT.value.selectAudio.name = ''
@@ -1354,27 +1695,23 @@
const removeHtmlTags = (html) => {
  const parser = new DOMParser()
  const doc = parser.parseFromString(html, 'text/html')
  return doc.body.textContent || ""
  return doc.body.textContent || ''
}
const saveSubmit = async (type) => {
  console.log( "是否删除", DeleteD.value )
  console.log('是否删除', DeleteD.value)
  if (!PPTArr.value || PPTArr.value.length === 0) {
    message.warning('场景为空,请先上传PPT!')
    return false
  }
  //人脸校验
  while(!IsEndCheckFace.value){} //一个空循环,主要为了避免极端情况下当用户点击保存按钮或者视频合成按钮时,人脸校验未完成的问题
  if( IsHaveFace.value && !DeleteD.value ){
  while (!IsEndCheckFace.value) {} //一个空循环,主要为了避免极端情况下当用户点击保存按钮或者视频合成按钮时,人脸校验未完成的问题
  if (IsHaveFace.value && !DeleteD.value) {
    message.warning('当前ppt中存在人脸元素,为方便后续视频生成,请去除该元素')
    return
  }
  //保存课程
  let saveSubmitForm = {
@@ -1453,15 +1790,19 @@
            marker: 1,
            status: item.digitalHuman?.show ? 0 : 1
          },
          ...(item.innerPicture?.src ? [{
            ...cloneDeep(item.innerPicture),
            width: item.innerPicture.width * scaleRatio.value.width,
            height: item.innerPicture.height * scaleRatio.value.height,
            top: item.innerPicture.top * scaleRatio.value.height,
            marginLeft: item.innerPicture.marginLeft * scaleRatio.value.width,
            category: 1,
            id: undefined
          }] : [])
          ...(item.innerPicture?.src
            ? [
                {
                  ...cloneDeep(item.innerPicture),
                  width: item.innerPicture.width * scaleRatio.value.width,
                  height: item.innerPicture.height * scaleRatio.value.height,
                  top: item.innerPicture.top * scaleRatio.value.height,
                  marginLeft: item.innerPicture.marginLeft * scaleRatio.value.width,
                  category: 1,
                  id: undefined
                }
              ]
            : [])
        ],
        driverType: item.driverType,
        duration: '',
@@ -1472,7 +1813,7 @@
          speech_rate: voiceData.speechRate,
          volume: voiceData.volume,
          smartSpeed: '',
          textJson: item.pptRemark,
          textJson: item.pptRemark
        },
        audioDriver: {
          fileName: item.fileList && item.fileList[0]?.name,
@@ -1503,13 +1844,12 @@
  saveSubmitForm.scenes = cloneDeep(scenes)
  if (type == 'save') {
    if( DeleteD.value ){
    if (DeleteD.value) {
      //如果进行过ppt删除操作则需要进行二次查看
      await PPtIsHaveFace()
      if( IsHaveFace.value ){
          message.warning('当前ppt中存在人脸元素,为方便后续视频生成,请去除该元素')
          return
      if (IsHaveFace.value) {
        message.warning('当前ppt中存在人脸元素,为方便后续视频生成,请去除该元素')
        return
      }
    }
@@ -1528,6 +1868,11 @@
    }
  } else {
    try {
      if (ChangeSoundTypeList.value?.value === undefined || selectLanguage.value?.value === undefined) {
        message.error('请先选择语种与声音类型')
        return
      }
      const saveResult = await saveSubmit('save')
      if (!saveResult) {
        message.error('保存失败,请重试后再合成视频')
@@ -1538,8 +1883,8 @@
      for (let i = 0; i < PPTArr.value.length; i++) {
        const item = PPTArr.value[i]
        console.log(item)
        console.log( "宽度", item.width )
        console.log( "高度", item.height )
        console.log('宽度', item.width)
        console.log('高度', item.height)
        // 校验背景宽高
        if (!item.width || !item.height) {
          message.warning('背景尺寸无效,请检查宽高设置,或者重新选择模板')
@@ -1606,7 +1951,7 @@
          originHeight: courseInfo.value.height,
          originWidth: courseInfo.value.width,
          entityId: 1,
          templateId: template.id,
          templateId: template.id
        }
      }
    } else {
@@ -1665,6 +2010,11 @@
const currentAudio = ref()
const createAudio = async () => {
  if (ChangeSoundTypeList.value?.value === undefined || selectLanguage.value?.value === undefined) {
    message.error('请先选择语种与声音类型')
    return
  }
  const text = editorRef.value.getText()
  if (!text) {
    message.warning('请输入需要试听文本的内容…')
@@ -1677,7 +2027,7 @@
    text: truncatedText,
    humanId: selectPPT.value.digitalHuman?.host?.id || null,
    // voiceId: audioSelectData.value == undefined ? null : audioSelectData.value[0].id,
    voiceId: 'zh-CN',
    voiceId: 'zh-CN'
  }
  try {
@@ -1799,12 +2149,12 @@
  // 限制坐标
  if (data.x < -100) {
    data.x = -100; // 可以设置最小坐标为 -100
    data.x = -100 // 可以设置最小坐标为 -100
  }
  if (data.y < -100) {
    data.y = -100; // 可以设置最小坐标为 -100
    data.y = -100 // 可以设置最小坐标为 -100
  }
};
}
const getCourseDetail = async (id) => {
  const res = await pptTemplateApi.coursesDetail(id)
@@ -1831,7 +2181,7 @@
            h: hostInfo.height / scaleRatio.value.height,
            active: false,
            host: {
              ...hostList.value.find(h => h.code === hostInfo.entityId),
              ...hostList.value.find((h) => h.code === hostInfo.entityId),
              code: hostInfo.entityId,
              type: hostInfo.entityType
            }
@@ -1901,7 +2251,6 @@
    }))
    templates.value = TEMPLATE_PRESETS.value.map((template) => cloneDeep(template))
    selectTemplate.value = cloneDeep(templates.value[0])
  }
}
onMounted(async () => {
@@ -2452,7 +2801,91 @@
    background-color: #1989fa;
  }
}
.dialog-footer{
.dialog-footer {
  float: right;
}
// 声音部分
.SoundArea {
  margin-top: 10px;
  height: 100%;
  .SoundClassArea {
    width: 100%;
    display: flex;
    justify-content: space-around;
    align-items: center;
    > div {
      width: 30%;
    }
  }
  .SoundModelArea {
    width: 100%;
    height: 86%;
    margin: 10px 0;
    overflow-y: scroll;
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    > .ModealBox {
      width: 30%;
      margin: 10px 1%;
      position: relative;
      > .ImgBox {
        width: 70%;
        margin: 0 auto;
        img {
          width: 100%;
        }
      }
      > .TextArea {
        width: 100%;
        p {
          margin: 3px 0;
          padding-left: 6px;
          box-sizing: border-box;
          text-align: left;
          word-wrap: break-word;
        }
      }
      > .play-img {
        width: 32px;
        height: 32px;
        cursor: pointer;
        position: absolute;
        top: 0;
        right: 0;
        left: 0;
        bottom: 0;
        margin: auto;
        z-index: +10;
      }
    }
    .ModealBox:hover {
      background-color: #000;
      opacity: 0.5;
      border: 2px solid #0183f4;
      > .TextArea {
        p {
          color: #fff;
        }
      }
    }
    > .slectModel {
      border: 2px solid #1989fa;
      border-radius: 6px;
    }
  }
  .ButtonArea {
    width: 90%;
    margin: 0 auto;
    display: flex;
    justify-content: space-around;
    align-items: center;
    button {
      width: 90%;
      padding: 20px 0;
      box-sizing: border-box;
    }
  }
}
</style>