| | |
| | | <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" |
| | |
| | | </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"> |
| | |
| | | </el-tooltip> |
| | | </div> |
| | | </div> |
| | | <!-- 数字人 --> |
| | | <div class="template-box template-right" v-if="showDigitalHumanTool"> |
| | | <div class="tabs-1"> |
| | | <div |
| | |
| | | :key="index" |
| | | :style="{ |
| | | width: '90%', |
| | | maxWidth: '90%', |
| | | maxWidth: '90%' |
| | | }" |
| | | @click="handleTemplateSelection(template)" |
| | | > |
| | |
| | | <!-- <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"> |
| | |
| | | <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> |
| | |
| | | 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' |
| | |
| | | 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() |
| | |
| | | |
| | | const pagesToUpdate = applyAllHost.value ? PPTArr.value : [selectPPT.value] |
| | | |
| | | pagesToUpdate.forEach(page => { |
| | | pagesToUpdate.forEach((page) => { |
| | | page.digitalHuman.host = host |
| | | initHumanPositon(host, page.digitalHuman) |
| | | }) |
| | |
| | | activeUrl: userActive, |
| | | isActive: false |
| | | }, |
| | | // 声音类型 |
| | | { |
| | | name: t('courseCenter.sound'), |
| | | url: sound, |
| | | activeUrl: soundActive, |
| | | isActive: false |
| | | } |
| | | // { |
| | | // name: t('courseCenter.background'), |
| | | // url: bg, |
| | |
| | | |
| | | const showHeadImageTool = ref(false) |
| | | const showDigitalHumanTool = ref(false) |
| | | // 声音 |
| | | const SoundTool = ref(false) |
| | | const showTemplateTool = ref(false) |
| | | const showInnerPictureTool = ref(false) |
| | | const applyAllTemplate = ref(false) |
| | |
| | | tabs4ActiveNum.value = '2' |
| | | 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([]) |
| | |
| | | } |
| | | |
| | | const copyDocument = (item, index) => { |
| | | ElMessageBox.confirm( |
| | | '是否复制该页面?', |
| | | '提示', |
| | | { |
| | | ElMessageBox.confirm('是否复制该页面?', '提示', { |
| | | confirmButtonText: '是', |
| | | cancelButtonText: '否', |
| | | type: 'warning', |
| | | }).then(() => { |
| | | 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(() => { |
| | | }) |
| | | .catch(() => { |
| | | ElMessage({ |
| | | type: 'info', |
| | | message: '已取消复制', |
| | | message: '已取消复制' |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | const deleteDocument = (item) => { |
| | | ElMessageBox.confirm( |
| | | '是否删除该页面?', |
| | | '提示', |
| | | { |
| | | ElMessageBox.confirm('是否删除该页面?', '提示', { |
| | | confirmButtonText: '是', |
| | | cancelButtonText: '否', |
| | | type: 'warning', |
| | | } |
| | | ).then(() => { |
| | | type: 'warning' |
| | | }) |
| | | .then(() => { |
| | | PPTArr.value = PPTArr.value.filter((child) => child.id !== item.id) |
| | | //已经进行过删除操作 |
| | | DeleteD.value = true |
| | | }).catch(() => { |
| | | }) |
| | | .catch(() => { |
| | | ElMessage({ |
| | | type: 'info', |
| | | message: '已取消删除', |
| | | message: '已取消删除' |
| | | }) |
| | | }) |
| | | } |
| | |
| | | } |
| | | |
| | | const selectAudio = (data) => { |
| | | console.log(data) |
| | | audioSelectData.value = data |
| | | if (data == undefined) { |
| | | selectPPT.value.selectAudio.name = '' |
| | |
| | | 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){} //一个空循环,主要为了避免极端情况下当用户点击保存按钮或者视频合成按钮时,人脸校验未完成的问题 |
| | |
| | | message.warning('当前ppt中存在人脸元素,为方便后续视频生成,请去除该元素') |
| | | return |
| | | } |
| | | |
| | | |
| | | |
| | | //保存课程 |
| | | let saveSubmitForm = { |
| | |
| | | marker: 1, |
| | | status: item.digitalHuman?.show ? 0 : 1 |
| | | }, |
| | | ...(item.innerPicture?.src ? [{ |
| | | ...(item.innerPicture?.src |
| | | ? [ |
| | | { |
| | | ...cloneDeep(item.innerPicture), |
| | | width: item.innerPicture.width * scaleRatio.value.width, |
| | | height: item.innerPicture.height * scaleRatio.value.height, |
| | |
| | | marginLeft: item.innerPicture.marginLeft * scaleRatio.value.width, |
| | | category: 1, |
| | | id: undefined |
| | | }] : []) |
| | | } |
| | | ] |
| | | : []) |
| | | ], |
| | | driverType: item.driverType, |
| | | duration: '', |
| | |
| | | speech_rate: voiceData.speechRate, |
| | | volume: voiceData.volume, |
| | | smartSpeed: '', |
| | | textJson: item.pptRemark, |
| | | textJson: item.pptRemark |
| | | }, |
| | | audioDriver: { |
| | | fileName: item.fileList && item.fileList[0]?.name, |
| | |
| | | saveSubmitForm.scenes = cloneDeep(scenes) |
| | | |
| | | if (type == 'save') { |
| | | |
| | | if( DeleteD.value ){ |
| | | //如果进行过ppt删除操作则需要进行二次查看 |
| | | await PPtIsHaveFace() |
| | |
| | | } |
| | | } else { |
| | | try { |
| | | if (ChangeSoundTypeList.value?.value === undefined || selectLanguage.value?.value === undefined) { |
| | | message.error('请先选择语种与声音类型') |
| | | return |
| | | } |
| | | |
| | | const saveResult = await saveSubmit('save') |
| | | if (!saveResult) { |
| | | message.error('保存失败,请重试后再合成视频') |
| | |
| | | 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('背景尺寸无效,请检查宽高设置,或者重新选择模板') |
| | |
| | | originHeight: courseInfo.value.height, |
| | | originWidth: courseInfo.value.width, |
| | | entityId: 1, |
| | | templateId: template.id, |
| | | templateId: template.id |
| | | } |
| | | } |
| | | } else { |
| | |
| | | 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('请输入需要试听文本的内容…') |
| | |
| | | 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 { |
| | |
| | | |
| | | // 限制坐标 |
| | | 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) |
| | |
| | | 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 |
| | | } |
| | |
| | | })) |
| | | templates.value = TEMPLATE_PRESETS.value.map((template) => cloneDeep(template)) |
| | | selectTemplate.value = cloneDeep(templates.value[0]) |
| | | |
| | | } |
| | | } |
| | | onMounted(async () => { |
| | |
| | | .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> |