|
- <template>
- <div class="page flex justify-around">
- <!-- 左侧栏 -->
- <div class="left ">
- <!-- 顶部 -->
- <!-- 选中AiFace -->
- <div class="left-top" v-show="showUploadBtn == 1" >
- <el-row class="justify-between">
- <!-- title框 v-show="!submitImgBtn"-->
- <div
- v-show="showUploadBtn == 1"
- class="flex justify-between"
- style="width: 300px"
- >
- <el-input
- maxlength="15"
- v-model="title"
- :placeholder="$t('createVideo.typeTitle')"
- />
- <el-icon class="icon-edit"><i-ep-edit /></el-icon>
- <!-- 编辑字幕框 -->
- </div>
- <div v-if="imgUrl&&SubtitlesSwitch" class="editSubtitlesBox ">
- <!-- 字体 -->
- <div class="item">{{$t('createVideo.fontFamily')}}: <el-select v-model="SubtitlesFontFamily" style="width: 80px;" placeholder=" " size="small">
- <el-option
- v-for="item in fontFamilyList"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select></div>
- <!-- Y轴 -->
- <div v-show="false" class="item">{{$t('createVideo.YAxis')}}: <el-input
- v-model="SubtitlesTop"
- width="30"
- /></div>
- <!-- X轴 -->
- <div v-show="false" class="item" style="">{{$t('createVideo.XAxis')}}: <el-input
- v-model="SubtitlesLeft"
- width="30"
- /></div>
- <!-- 单双行 -->
- <div class="item" >{{$t('createVideo.rows')}}: <el-switch
- v-model="SubtitlesRow"
- inline-prompt
- style="--el-switch-on-color: #000; --el-switch-off-color: #13ce66;"
- :active-text="$t('createVideo.rows2')"
- :inactive-text="$t('createVideo.rows1')"
- /></div>
- <!-- 字号大小 -->
- <div class="item">{{$t('createVideo.fontSize')}}: <el-input
- v-model="SubtitlesSize"
- width="30"
- /></div>
- <!-- 字幕盒子宽度 -->
- <div v-if="false" class="item">{{$t('createVideo.width')}}: <el-input
- v-model="SubtitlesWidth"
- width="30"
- /></div>
- <!-- 字色 -->
- <div class="item">
-
- <el-tooltip
- class="box-item"
- effect="dark"
- :content="$t('createVideo.FontColor')"
- placement="bottom"
- >
- <img style=" max-width: 15px;
- max-height: 15px;" src="../../assets/img/font.png" alt="">
- </el-tooltip>
-
- :
- <div @click="handleSubtitlesColorShow" class="myColorBox" :style="{backgroundColor: SubtitlesColor}">
- <div v-show="SubtitlesColorShow" class="selectColor">
- <div v-for="item in colorList" :style="{backgroundColor: item}" class="selectColor-item" @click="SubtitlesColor=item"></div>
- </div>
- </div>
- </div>
- <!-- 背景色 -->
- <div class="item"> <el-tooltip
- class="box-item"
- effect="dark"
- :content="$t('createVideo.backgroundColor')"
- placement="bottom"
- >
- <img style=" max-width: 25px;
- max-height: 25px;" src="../../assets/img/bgc.png" alt="">
- </el-tooltip>:
- <div @click="handleSubtitlesBgcShow" class="myColorBox" :style="{backgroundColor: SubtitlesBgc}">
- <div v-show="SubtitlesBgcShow" class="selectColor">
- <div v-for="item in colorList" :style="{backgroundColor: item}" class="selectColor-item" @click="SubtitlesBgc=item"></div>
- </div>
- </div>
- </div>
- </div>
- </el-row>
- <!-- 中间展示大图 -->
- <div ref="canvasImgBox" class="bigImg inmiddle">
- <img id="canvasImg" :src="imgUrl" alt="" class="" />
- <div id="SubtitlesBox" ref="SubtitlesBox" @mousedown="handleDrag" :style="SubtitlesStyle" v-if="SubtitlesSwitch" class="SubtitlesBox">
- <div class="SubtitlesTip">{{$t('createVideo.SubtitlesTip')}}</div>
- <div v-show="SubtitlesRow" class="SubtitlesTip">{{$t('createVideo.SubtitlesTip')}}</div>
- <div class="stretchBox box1"></div>
- <div class="stretchBox box2"></div>
- <div class="stretchBox box3"></div>
- <div class="stretchBox box4" @mousedown="startResize2"
- ></div>
- <div class="stretchBox box5" @mousedown="startResize"
- ></div>
- <div class="stretchBox box6"></div>
- <div class="stretchBox box7"></div>
- <div class="stretchBox box8"></div>
- <div v-show="false" class="stretchBox box9" @mousedown="startRotation" @mousemove="rotateBox" @mouseup="stopRotation"></div>
- </div>
-
- </div>
- <!-- 字幕开关 -->
- <div v-if="imgUrl" class="SubtitlesSwitch">
- <p>{{ $t('createVideo.subtitles') }}</p>
- <el-switch v-model="SubtitlesSwitch" style="--el-switch-on-color: #000"/>
- </div>
- </div>
- <!-- 选中需要上传的图片前 -->
- <div class="left-top" v-show="showUploadBtn == 2">
- <!-- 中间展示大图 -->
- <div class="noImg">
- <my-loading
- style="margin-top: 150px"
- :isLoading="compressionImgLoad"
- ></my-loading>
- <div v-if="!compressionImgLoad" class="trueImg inmiddle">
- <div class="imgBox">
- <img src="../../assets/img/trueImg.png" alt="" />
- </div>
- <div class="icon">✔</div>
- </div>
- <div v-if="!compressionImgLoad" class="upload inmiddle">
- <p>
- <!-- <el-icon><i-ep-FolderAdd /></el-icon> -->
- <img src="../../assets/img/uploadImg.png" alt="" />
- </p>
- <span>{{ $t("createVideo.uploadImgTip1") }}</span>
- <span>{{ $t("createVideo.uploadImgTip2") }}</span>
- <input accept="image/*" type="file" @change="lookImg" />
- </div>
- <div v-if="!compressionImgLoad" class="falseImg inmiddle">
- <div>
- <div class="imgBox">
- <img src="../../assets/img/false1.png" alt="" />
- </div>
- <div class="icon">×</div>
- </div>
- <div>
- <div class="imgBox">
- <img src="../../assets/img/false2.png" alt="" />
- </div>
- <div class="icon">×</div>
- </div>
- <div>
- <div class="imgBox">
- <img src="../../assets/img/false3.png" alt="" />
- </div>
- <div class="icon">×</div>
- </div>
- </div>
- </div>
- </div>
- <!-- loading -->
- <div class="left-top" v-show="showUploadBtn == 3">
- <!-- 中间展示大图 -->
- <div class="noImg">
- <my-loading
- style="margin-top: 150px"
- :isLoading="compressionImgLoad"
- :tips="imgUploadTips"
- ></my-loading>
- </div>
- </div>
- <!-- 选中需要上传的图片后 -->
- <div class="left-top" v-show="showUploadBtn == 4">
- <el-row style="display: flex; justify-content: flex-end">
- <!-- 上传按钮 废弃了-->
- <!-- <div v-if="false" class="btnBox" v-show="submitImgBtn"> -->
- <div v-if="false" class="btnBox">
- <button class="uploadBtn">
- {{ $t("createVideo.reselect") }}
- <input accept="image/*" type="file" @change="lookImg" />
- </button>
- <button class="uploadBtn" @click="changeFile">
- {{ $t("createVideo.sureUpload") }}
- </button>
- </div>
- </el-row>
- <!-- 中间展示大图 -->
- <div class="bigImg inmiddle">
- <img :src="imgUrl" alt="" class="inmiddle" />
- </div>
- </div>
- <!-- AI生成图片展示区 -->
- <div class="left-top" v-show="showUploadBtn == 5">
- <div class="editAiPicBox">
- <div class="edit">
- <div class="TagBox"></div>
- </div>
- <div class="AIpicBox">
- <div class="picBox">
- <img src="../../assets/img/trueImg.png" alt="" />
- </div>
- </div>
- </div>
- </div>
-
- <!-- 底部 -->
- <div class="left-bottom">
- <!-- tab栏 -->
- <div class="tab flex">
- <div
- class="pointer"
- :class="showFace == 0 ? 'tabAvtive' : ''"
- @click="chooSystemImg"
- >
- {{ $t("createVideo.availableMould") }}
- </div>
- <div
- class="pointer"
- :class="showFace == 1 ? 'tabAvtive' : ''"
- @click="chooseMyImg"
- >
- {{ $t("createVideo.personalWarehouse") }}
- </div>
- <div
- class="pointer aiPicTab"
- :class="showFace == 2 ? 'tabAvtive' : ''"
- @click="chooseAiPic"
- >
- <div class="subscript subscript1">
- <!-- <span>AI </span> -->
- <img src="../../assets/img/aitoface.png" alt="" />
- </div>
- {{ $t("createVideo.Aipicture") }}
- </div>
- </div>
- <!-- 系统相册 -->
- <div
- class="faceList"
- v-if="showFace == 0"
- v-infinite-scroll="loadMoreAiFaceSystem"
- :infinite-scroll-disabled="overLoadSystem"
- infinite-scroll-distance="10"
- >
- <!-- 上传图片组件 -->
- <div v-if="showFace == 1" class="faceItem" @click="clickAddBtn">
- <span class="uploadImg">+ </span>
- </div>
- <my-loading :isLoading="feceItemLoading"></my-loading>
- <!-- face列表 -->
- <div
- :class="faceItemActive == item.id ? 'faceItemActive' : ''"
- class="faceItem pointer"
- @click="setImgUrl(item.material, item.id)"
- v-for="item in AiFaceList"
- :key="item.id"
- >
- <div class="imgBox">
- <img :src="item.material" alt="" />
- </div>
- s
- </div>
- </div>
- <!-- 个人相册 -->
- <div
- class="faceList"
- v-if="showFace == 1"
- v-infinite-scroll="loadMoreAiFaceUser"
- :infinite-scroll-disabled="overLoadUser"
- infinite-scroll-distance="10"
- >
- <!-- 上传图片组件 -->
- <div v-if="showFace == 1" class="faceItem" @click="clickAddBtn">
- <span class="uploadImg">+ </span>
- </div>
- <my-loading :isLoading="feceItemLoading2"></my-loading>
- <!-- face列表 -->
- <div
- :class="faceItemActive == item.id ? 'faceItemActive' : ''"
- class="faceItem pointer"
- @click="setImgUrl(item.material, item.id)"
- v-for="item in userAiFaceList"
- :key="item.id"
- >
- <div class="imgBox">
- <img :src="item.material" alt="" />
- </div>
- <div
- v-if="faceItemActive == item.id"
- @click="deleteFaceImg(item.id)"
- class="deleteIcon"
- >
- ✖︎
- </div>
- </div>
- </div>
- <!-- AI生成图片 -->
- <div
- class="Aipicture"
- v-if="showFace == 2"
-
- >
- <div class="title">
- <el-icon><i-ep-Lock /></el-icon>
- {{ $t("createVideo.comingSoon") }}
- </div>
- </div>
- </div>
- </div>
- <!-- 右侧栏 -->
- <div class="right scrolly">
- <div class="subscript">
- <!-- <span>GPT</span> -->
- <img src="../../assets/img/gpttotext.png" alt="" />
- </div>
- <el-tabs @tab-click="clickTab4" type="border-card" class="tabs">
- <!-- ----------------------------- 1 -->
- <el-tab-pane :label="$t('createVideo.typeScript')">
- <div class="card1">
- <div class="text">
- <!-- 文本域 -->
- <el-input
- maxlength="500"
- id="textInputId"
- v-model="textareaContent"
- :rows="12"
- type="textarea"
- :placeholder="$t('createVideo.aiText')"
- />
- <div class="sundriesBox">
- <span v-if="false" class="pointer" @click="getPreviewAudio">
- <el-tooltip
- class="box-item"
- effect="dark"
- :content="$t('createVideo.tooltip1')"
- placement="top"
- >
- 🔊
- </el-tooltip></span
- >
- <my-Loading-Icon
- class="previewAudioLoadingBox"
- v-if="false"
- ></my-Loading-Icon>
- <span class="pointer" @click="insertIcon">
- <el-tooltip
- class="box-item"
- effect="dark"
- :content="$t('createVideo.tooltip2')"
- placement="bottom"
- >
- 🕗
- </el-tooltip></span
- >
- <i
- >{{ $t("createVideo.entered") }}
- {{ textareaContent.length }} / 500</i
- >
- </div>
- </div>
- <p>{{ $t("createVideo.languages") }}</p>
- <!-- 语言 -->
- <el-select
- @change="chooseType"
- v-model="language"
- :placeholder="$t('createVideo.select')"
- style="width: 100%"
- >
- <!-- :label="lanChange == 'zh-cn' ? item.chineseName : item.name" -->
- <el-option
- v-for="item in languageOptions"
- :key="item.value"
- :label="lanChange == 'zh-cn' ? item.chineseName : item.name"
- :value="item.id"
- >
- <img
- :src="item.img"
- alt=""
- style="
- width: 20px;
- margin-right: 10px;
- vertical-align: text-top;
- "
- />
- <span style="line-height: 20px">{{
- lanChange == "zh-cn" ? item.chineseName : item.name
- }}</span>
- </el-option>
- </el-select>
- <p>{{ $t("createVideo.voices") }}</p>
- <!-- 声音 -->
- <el-select
- @change="chooseStyle"
- :disabled="language ? false : true"
- v-model="sound"
- :placeholder="$t('createVideo.select')"
- style="width: 100%"
- >
- <el-option
- v-for="item in soundOptions"
- :key="item.value"
- :label="
- (lanChange == 'zh-cn'
- ? item.displayName +
- ` (${item.sex == 1 ? '男' : '女'})`
- : item.localName +
- ` (${item.sex == 1 ? 'male' : 'female'})`) +
- returnAge(item.ageType)
- "
- :value="item.id"
- />
- </el-select>
- <p>{{ $t("createVideo.styles") }}</p>
- <!-- 风格 -->
- <el-select
- :disabled="soundStyleOptions ? false : true"
- v-model="soundStyle"
- :placeholder="$t('createVideo.select')"
- style="width: 100%"
- >
- <el-option
- v-for="item in soundStyleOptions"
- :key="item.name"
- :label="lanChange == 'zh-cn' ? item.name : item.engName"
- :value="item.name"
- >
- <div style="padding: 0 20px">
- {{ lanChange == "zh-cn" ? item.name : item.engName }}
- <span
- style="float: right; cursor: pointer"
- @click.stop="ListenVoices(item.url)"
- >🔊</span
- >
- </div>
- <!-- <span class="pointer" @click="getPreviewAudio">
- <el-tooltip
- v-if="false"
- class="box-item"
- effect="dark"
- :content="$t('createVideo.tooltip1')"
- placement="top"
- >
-
- </el-tooltip></span > -->
- </el-option>
- </el-select>
- <!-- 保存视频 -->
- <el-button
- @click="saveOrUpdate(1, 'saveVideo')"
- color="#000"
- type="primary"
- >
- <my-loading :isLoading="createLoading"></my-loading>
- <span v-if="!createLoading">{{
- $t("createVideo.saveVideo")
- }}</span></el-button
- >
- <!-- 生成视频 -->
- <el-button
- style="margin-left: 0"
- @click="saveOrUpdate(1)"
- color="#000"
- type="primary"
- >
- <my-loading :isLoading="createLoading"></my-loading>
- <span v-if="!createLoading">{{
- $t("createVideo.generateVideo")
- }}</span></el-button
- >
- </div>
- </el-tab-pane>
- <!-- ------------------------ 2 -->
- <el-tab-pane :label="$t('createVideo.uploadAudio')">
- <div class="card2">
- <!-- 上传音频 -->
- <p>
- <el-icon class="icon-Headset"><i-ep-Headset /></el-icon>
- {{ $t("createVideo.uploadAudio") }}
-
- <div class="overtimeTips" style="float: right">
- <img src="../../assets/img/tips.png" alt="" />
- {{
- lanChange == "zh-cn"
- ? `免费用户限制为60秒!`
- : `Free user limit 60 seconds!`
- }}
- </div>
-
- </p>
- <div
- class="uploadVideo"
- :class="
- audioUrl && showAudioWhich == 1 ? 'uploadAudioAvtion2' : ''
- "
- >
- <!-- <el-icon><i-ep-FolderAdd /></el-icon> -->
- <!-- <div>
- </div> -->
- <img src="../../assets/img/uploadImg.png" alt="" />
- <!-- fileInput.value.files[0] e.target.value = null -->
- <input
- accept="audio/*"
- type="file"
- ref="fileInput"
- @click="handleFileClick"
- @change="handleFileChange"
- />
- <div class="AudioBox" v-if="audioUrl && showAudioWhich == 1">
- <audio controls :src="audioUrl" id="uploadAudio"></audio>
- </div>
- </div>
-
- <!-- 录制MP3上传语音 -->
- <p>
- <el-icon class="icon-Mic"><i-ep-Mic /></el-icon>
- {{ $t("createVideo.recordedAudio") }}
- <div class="overtimeTips" style="float: right">
- <img src="../../assets/img/tips.png" alt="" />
- {{
- lanChange == "zh-cn"
- ? `免费用户限制为60秒!`
- : `Free user limit 60 seconds!`
- }}
- </div>
- </p>
- <div
- class="uploadAudio"
- :class="
- audioUrl && showAudioWhich == 2 ? 'uploadAudioAvtion' : ''
- "
- >
- <div class="btnBox">
- <button
- class="pointer"
- :disabled="!isRecording"
- @click="startRecording"
- >
- {{ $t("createVideo.startRecorded") }}
- <div v-if="isRecording" class="pointer">
- <el-icon><i-ep-VideoPlay /></el-icon>
- </div>
-
- <div v-if="!isRecording" class="pointer">
- <el-icon><i-ep-VideoPause /></el-icon>
- </div>
- </button>
- {{ formatTime(duration) }}
- <button
- class="pointer"
- @click="stopRecording"
- :disabled="isRecording"
- >
- {{ $t("createVideo.stopRecorded") }}
- <div class="pointer">
- <el-icon><i-ep-SwitchButton /></el-icon>
- </div>
- </button>
- </div>
- <div class="AudioBox" v-if="audioUrl && showAudioWhich == 2">
- <audio controls :src="audioUrl" id="uploadAudio"></audio>
- </div>
- </div>
- <!-- <div class="AudioBox" v-if="audioUrl">
- <audio controls :src="audioUrl" id="uploadAudio"></audio>
- </div> -->
- <!-- 保存视频 -->
- <el-button
- @click="saveOrUpdate(2, 'saveVideo')"
- color="#000"
- type="primary"
- >
- <my-loading :isLoading="createLoading"></my-loading>
- <span v-if="!createLoading">{{
- $t("createVideo.saveVideo")
- }}</span></el-button
- >
- <!-- 生成视频 -->
- <el-button
- style="margin-left: 0"
- @click="saveOrUpdate(2)"
- color="#000"
- type="primary"
- >
- <my-loading :isLoading="createLoading"></my-loading>
- <span v-if="!createLoading">{{
- $t("createVideo.generateVideo")
- }}</span>
- </el-button>
- </div>
- </el-tab-pane>
- <!-- ----------------------- 3 -->
- <el-tab-pane :label="$t('createVideo.music')">
- <div class="card3">
-
- <!-- 选择音乐 -->
- <p>
- <el-icon class="icon-Headset"><i-ep-Headset /></el-icon>
- {{ $t("createVideo.chooseMusic") }}
- </p>
- <!-- tab栏 -->
- <div class="musicTab">
- <div
- class="musicTabItem"
- :class="musicTabActive == 1 ? 'musicTabItemActive' : ''"
- @click="musicTabActiveChange(1)"
- >
- {{ $t("createVideo.hotMusic") }}
- </div>
- <div
- class="musicTabItem"
- :class="musicTabActive == 2 ? 'musicTabItemActive' : ''"
- @click="musicTabActiveChange(2)"
- >
- {{ $t("createVideo.personalWarehouse") }}
- </div>
- </div>
- <!-- 上传音乐 -->
- <div class="overtimeTips" v-if="musicTabActive == 2" style="margin-top: 5px;">
- <img src="../../assets/img/tips.png" alt="" />
- {{
- lanChange == "zh-cn"
- ? `免费用户限制为60秒!`
- : `Free user limit 60 seconds!`
- }}
- </div>
- <div v-if="musicTabActive == 2" class="uploadVideo">
- <!-- <el-icon><i-ep-FolderAdd /></el-icon> -->
- <div class="imgInCenter">
- <img src="../../assets/img/uploadImg.png" alt="" />
- </div>
- <input
- accept="audio/*"
- type="file"
- ref="fileMusicInput"
- @click="handleFileMusicClick"
- @change="uploadMusic"
- />
- </div>
- <!-- 系统音乐列表展示 -->
- <div v-if="musicTabActive == 1" class="musicList">
- <div
- @click="chooseMusicUrl(item)"
- class="musicItem"
- :class="musicItemAction == item.id ? 'musicItemAvtive' : ''"
- v-for="item in musicListSystem"
- :key="item.id"
- >
- <span class="musicNmae"> 🎵{{ item.name }}</span>
- <span class="musicTime"> {{ handleTime(item.time) }}</span>
- </div>
- </div>
- <!-- 个人音乐列表展示 -->
- <div v-if="musicTabActive == 2" class="musicList">
- <div
- @click="chooseMusicUrl(item)"
- class="musicItem"
- :class="musicItemAction == item.id ? 'musicItemAvtive' : ''"
- v-for="item in musicListPerson"
- :key="item.id"
- >
- <span class="musicNmae"> 🎵{{ item.name }}</span>
- <span class="musicTime"> {{ handleTime(item.time) }}</span>
- <span
- v-if="musicItemAction == item.id"
- class="delMusic"
- @click="deleteMusic(item.id)"
- ><el-icon><i-ep-Delete /></el-icon>
- </span>
- </div>
- </div>
- <!-- 系统分页 -->
- <div
- v-if="musicTabActive == 1 && musicListTotalSystem"
- class="pagination"
- >
- <el-pagination
- v-model:current-page="musicListPageNumSystem"
- v-model:page-size="musicListPageSize"
- :small="false"
- :disabled="false"
- :background="true"
- layout="total, prev, pager, next, jumper"
- :total="musicListTotalSystem"
- @current-change="musicListPageNumSystemChange"
- />
- </div>
- <!-- 个人分页 -->
- <div
- v-if="musicTabActive == 2 && musicListTotalPerson"
- class="pagination"
- >
- <el-pagination
- v-model:current-page="musicListPageNumPerson"
- v-model:page-size="musicListPageSize"
- :small="false"
- :disabled="false"
- :background="true"
- layout="total, prev, pager, next, jumper"
- :total="musicListTotalPerson"
- @current-change="musicListPageNumPersonChange"
- />
- </div>
- <div class="AudioBox" v-if="audioMusicUrl">
- <audio controls :src="audioMusicUrl" id="uploadAudio"></audio>
- </div>
- <!-- 保存视频 -->
- <el-button
- @click="saveOrUpdate(3, 'saveVideo')"
- color="#000"
- type="primary"
- >
- <my-loading :isLoading="createLoading"></my-loading>
- <span v-if="!createLoading">{{
- $t("createVideo.saveVideo")
- }}</span></el-button
- >
- <!-- 生成视频 -->
- <el-button
- style="margin-left: 0"
- @click="saveOrUpdate(3)"
- color="#000"
- type="primary"
- >
- <my-loading :isLoading="createLoading"></my-loading>
- <span v-if="!createLoading">{{
- $t("createVideo.generateVideo")
- }}</span>
- </el-button>
- </div>
- </el-tab-pane>
- <!-- ----------------------- 4 -->
- <el-tab-pane :label="$t('createVideo.aiScript')">
- <div class="card4">
- <!-- 语言 -->
- <div class="text">
- <!-- 文本域 -->
- <el-input
- maxlength="200"
- id="textInputId"
- v-model="problemContent"
- :rows="5"
- type="textarea"
- :placeholder="$t('createVideo.inputRequirement')"
- />
- </div>
- <el-button
- type="primary"
- :disabled="sendLoading"
- @click="sendRequirement"
- color="#000"
- >
- <my-Loading-Icon v-if="sendLoading"></my-Loading-Icon>
- <span v-if="!sendLoading">
- {{ $t("createVideo.GeneratedText") }}
- </span>
- </el-button>
-
- <p>{{ $t("createVideo.SmartText") }}</p>
- <!-- 语言 -->
- <div class="text" style="cursor: text">
- <!-- 文本域 -->
- <el-input
- maxlength="500"
- id="textInputId"
- v-model="answerContent"
- :rows="15"
- type="textarea"
- disabled=""
- />
- <i
- >{{ $t("createVideo.entered") }} {{ answerContent.length }} /
- 500</i
- >
- </div>
- <!-- <div class="card4Btn" @click="copyAnswerContent">
- {{ $t("createVideo.copy") }}
- </div> -->
- <el-button color="#000" @click="copyAnswerContent">
- {{ $t("createVideo.copy") }}
- </el-button>
- </div>
- </el-tab-pane>
- <!-- -------------------------脚标 -->
- </el-tabs>
- </div>
- <!-- 试听的mp3 -->
- <!-- style="opacity: 0; width: 0" -->
- <div>
- <audio muted autoplay :src="previewAudioUrl" id="audio"></audio>
- </div>
- </div>
- </template>
-
- <script setup>
- //#region 导入
- import { getCurrentInstance } from "vue";
- import {
- personPhotoList,
- personPhotoUserListList,
- awsImgUpload,
- delImgApi,
- baiduPhotoApi,
- checkFaceApi,
- videoUpload,
- saveImgApi,
- uploadProgressApi,
- saveAudioApi,
- voiceTotalApi,
- chooseTypeApi,
- saveOrUpdateApi,
- createVideoApi,
- previewAudioApi,
- findByIdApi,
- musicListSystemApi,
- musicListPersonApi,
- saveMusicApi,
- delMusicApi,
- } from "@/apis/createVideo";
- import { useI18n } from "vue-i18n";
- import Recorder from "js-audio-recorder"; //mp3插件
- import imageCompression from "browser-image-compression"; //压缩图片插件
- import { useRoute, useRouter } from "vue-router";
- import { fabric } from "fabric";
-
- //#endregion ---------------------------------
-
- const route = useRoute();
- const router = useRouter();
- const { locale } = useI18n();
- const lanChange = ref(locale);
-
- const AccessToken = localStorage.getItem("AccessToken"); // 判断有没有登录
-
- //#region 头像区的逻辑
- // 获取AI头像
- const AiFaceList = ref([]); //系统相册列表
- const userAiFaceList = ref([]); //个人相册列表
- const feceItemLoading = ref(false);
- const feceItemLoading2 = ref(false);
- const pageSize = ref(30); //加载页数
- function getAiFaceList(pageNum, pageSize, sendType) {
- feceItemLoading.value = true;
- personPhotoList(pageNum, pageSize, sendType)
- .then((res) => {
- AiFaceList.value = res.data.list;
- feceItemLoading.value = false;
- })
- .catch((err) => {
- feceItemLoading.value = false;
- console.log(err, "err");
- });
- }
- function getAiFaceUserList(pageNum, pageSize, sendType) {
- feceItemLoading2.value = true;
- personPhotoUserListList(pageNum, pageSize, sendType)
- .then((res) => {
- userAiFaceList.value = res.data.list;
- feceItemLoading2.value = false;
- })
- .catch((err) => {
- feceItemLoading2.value = false;
- console.log(err, "err");
- });
- }
- const pageNumSystem = ref(1);
- const overLoadSystem = ref(false); //禁用系统相册加载更多
- const pageNumUser = ref(1);
- const overLoadUser = ref(false); //禁用个人相册加载更多
- //系统相册触底加载更多
- function loadMoreAiFaceSystem() {
- pageNumSystem.value += 1;
- personPhotoList(pageNumSystem.value, pageSize.value, 1)
- .then((res) => {
- AiFaceList.value.push(...res.data.list);
- if (res.data.list.length == 0) {
- overLoadSystem.value = true;
- pageNumSystem.value = pageNumSystem.value - 1;
- }
- })
- .catch((err) => {
- console.log(err, "err");
- });
- }
- //个人相册触底加载更多
- function loadMoreAiFaceUser() {
- console.log(12333212311);
- pageNumUser.value += 1;
- personPhotoUserListList(pageNumUser.value, pageSize.value, 3)
- .then((res) => {
- if (res.data.list.length == 0) {
- overLoadUser.value = true;
- pageNumUser.value = pageNumUser.value - 1;
- }
- userAiFaceList.value.push(...res.data.list);
- })
- .catch((err) => {
- console.log(err, "err");
- });
- }
- // 选择显示的face列表
- const showFace = ref("0");
- function ChangeShowFaceList(index) {
- showFace.value = index;
- }
- const faceItemActive = ref(); //高亮处理和当前选择图片的ID
- // 点击aifece
- function setImgUrl(url, id) {
- faceItemActive.value = id; //高亮
- imgUrl.value = url; //回显地址
- showUploadBtn.value = 1; //
- // submitImgBtn.value = false;
- }
- // 删除个人相册照片
- async function deleteFaceImg(id) {
- const msg =
- lanChange.value == "zh-cn"
- ? `确定要删除这张图片吗? `
- : `Are you sure to delete this image ? `;
- const notice = lanChange.value == "zh-cn" ? "提示" : "Notice";
- const confirm = lanChange.value == "zh-cn" ? "确定" : "Confirm";
- const cancel = lanChange.value == "zh-cn" ? "取消" : "Cancel";
- ElMessageBox.confirm(msg, notice, {
- confirmButtonText: confirm,
- cancelButtonText: cancel,
- }).then(async () => {
- try {
- const res = await delImgApi(id);
- imgUrl.value = null;
- faceItemActive.value = null;
- userAiFaceList.value = [];
- getAiFaceUserList(1, pageSize.value, 3);
- pageNumUser.value = 1;
- overLoadUser.value = false;
- } catch (error) {
- ElMessage.error(
- lanChange.value == "zh-cn" ? `删除失败!` : `Deletion failure`
- );
- }
- });
- }
- //#endregion ------------------------------
-
- //#region 预览图片
- const imgUploadTips = ref(null); // 图片检测loading的文字提示
- const compressionImgLoad = ref(false);
- async function lookImg(e) {
- if (e.target.files[0]) {
- faceItemActive.value = null;
- imgUrl.value = null;
- imgData.value = null;
- showUploadBtn.value = 3;
- // submitImgBtn.value = false;
- compressionImgLoad.value = true;
- // 压缩配置
- const options = {
- maxSizeMB: 4, // 最大压缩大小为 4MB
- useWebWorker: true, // 使用 Web Worker 进行压缩,提高性能
- };
- imgUploadTips.value = "compress";
- const compressedFile = await imageCompression(e.target.files[0], options);
- imgUploadTips.value = "sensitiveness";
- try {
- const res = await baiduPhotoApi(compressedFile);
- if (res.code != 200) {
- throw new Error();
- }
- // 图片人脸信息检测通过时,继续检测敏感信息
- imgUploadTips.value = "chackFace";
- const res2 = await checkFaceApi(compressedFile);
- if (res2.code != 200) {
- throw new Error();
- }
- imgUrl.value = URL.createObjectURL(compressedFile);
- imgData.value = compressedFile;
- showUploadBtn.value = 4;
- // submitImgBtn.value = true;
- compressionImgLoad.value = false;
- await changeFile();
- } catch (error) {
- console.log(error, "上传图片的error");
- ElMessage.error(error.message);
- showFace.value = 1;
- showUploadBtn.value = 2;
- compressionImgLoad.value = false;
- imgUploadTips.value = null;
- }
- } else {
- return;
- }
- }
- // blob转base64
- function getImageBase64(blob) {
- return new Promise((resolve, reject) => {
- const reader = new FileReader();
- reader.readAsDataURL(blob);
- reader.onload = () => {
- const base64 = reader.result;
- resolve(base64);
- };
- reader.onerror = (error) => reject(error);
- });
- }
- //#endregion ------------------
-
- // 标题
- const title =
- lanChange.value == "zh-cn" ? ref("未定义标题") : ref("Undefined Title");
-
- //#region 上传图片
- const imgUrl = ref(""); //图片回显路径
- const imgData = ref(""); // 上传图片文件
- const showUploadBtn = ref(1); //上传图片+号的显示隐藏
- // const submitImgBtn = ref(false); //右上角俩按钮显示与隐藏
- // 点击系统仓库tab
- function chooSystemImg(params) {
- showFace.value = 0;
- showUploadBtn.value = 1;
- }
- // 上传图片
- async function changeFile() {
- imgUploadTips.value = "upLoadPictures";
- compressionImgLoad.value = true;
- showUploadBtn.value = 3;
- // imgUrl.value = URL.createObjectURL(imgData.value);
- let formData = new FormData();
- const timestamp = Date.now();
- formData.append("file", imgData.value, timestamp + ".png");
- try {
- // 上传图片
- const res = await awsImgUpload(formData);
- if (res.code != 200) {
- throw new Error();
- }
- // 保存图片
- const res2 = await saveImgApi({ material: res.data.url });
- if (res2.code != 200) {
- throw new Error();
- } else {
- ElMessage.success(
- lanChange.value == "zh-cn" ? `上传成功` : `Upload successfully`
- );
- }
- // 重新获取列表
- compressionImgLoad.value = false;
- showUploadBtn.value = 4;
- userAiFaceList.value = [];
- getAiFaceUserList(1, pageSize.value, 3);
- pageNumUser.value = 1;
- overLoadUser.value = false;
- faceItemActive.value = res2.data.id;
- imgUrl.value = res2.data.material;
- // submitImgBtn.value = false;
- showUploadBtn.value = 1;
- imgUploadTips.value = null;
- } catch (error) {
- ElMessage.error(lanChange.value == "zh-cn" ? `上传失败` : `Upload failure`);
- imgUrl.value = null;
- showFace.value = 1;
- showUploadBtn.value = 2;
- compressionImgLoad.value = false;
- imgUploadTips.value = null;
- }
- }
- // 点击个人仓库tab
- function chooseMyImg() {
- if (!AccessToken) {
- router.push({ path: "/login" });
- return;
- }
- showFace.value = 1;
- showUploadBtn.value = 2;
- }
- // 点击AI头像区的+号
- function clickAddBtn() {
- // 如果imgUploadTips有值,则
- if (imgUploadTips.value) {
- showUploadBtn.value = 3;
- submitImgBtn.value = false;
- compressionImgLoad.value = true;
- return;
- }
- showUploadBtn.value = 2;
- faceItemActive.value = null;
- }
- //#endregion ---------------------------
-
- //#region AI生成图片
- function chooseAiPic() {
- if (!AccessToken) {
- router.push({ path: "/login" });
- return;
- }
- showFace.value = 2;
- // showUploadBtn.value = 5;
- }
- //#endregion --------------------------
-
- //#region card1的逻辑
- const textareaContent = ref("");
- function insertIcon() {
- const textarea = document.getElementById("textInputId");
- const icon = "🕗"; // 这里使用了一个星星作为示例图标,你可以替换为你自己的图标
-
- // 获取光标位置
- const startPos = textarea.selectionStart;
- const endPos = textarea.selectionEnd;
-
- console.log(startPos);
- console.log(endPos);
- // 在光标位置插入图标
- textareaContent.value =
- textareaContent.value.substring(0, startPos) +
- icon +
- textareaContent.value.substring(endPos, textareaContent.value.length);
-
- // 设置光标位置为插入图标后的位置
- const newCursorPos = startPos + icon.length;
- textarea.setSelectionRange(newCursorPos, newCursorPos);
- textarea.focus();
- }
- const language = ref(""); //选择的语言
- const sound = ref(""); // 选择的声音
- const soundStyle = ref(""); //选择的风格
- // 语言下拉框内容
- const languageOptions = ref([]);
- async function voiceTotal() {
- try {
- const res = await voiceTotalApi();
- languageOptions.value = res.data;
- } catch (error) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `获取语言列表失败,请稍后重试`
- : `Failed to get the language list, please try again later`
- );
- }
- }
- // 声音下拉框内容
- const soundOptions = ref([]);
- async function chooseType() {
- const res = await chooseTypeApi(language.value);
- soundOptions.value = res.data;
- sound.value = null;
- }
- // 风格下拉框内容
- const soundStyleOptions = ref(null);
- async function chooseStyle() {
- const item = soundOptions.value.find((element) => element.id == sound.value);
- soundStyle.value = null;
- soundStyleOptions.value = item.style;
- }
- // 根据ageType返回年龄
- function returnAge(ageType) {
- if (!ageType) {
- return "";
- } else if (ageType == 1) {
- if (lanChange.value == "zh-cn") {
- return " 儿童";
- } else {
- return "Child";
- }
- } else if (ageType == 2) {
- if (lanChange.value == "zh-cn") {
- return " 少年";
- } else {
- return "Teen";
- }
- } else if (ageType == 3) {
- if (lanChange.value == "zh-cn") {
- return " 年轻";
- } else {
- return "YoungAdult";
- }
- } else if (ageType == 4) {
- if (lanChange.value == "zh-cn") {
- return " 中年";
- } else {
- return "OlderAdult";
- }
- } else if (ageType == 5) {
- if (lanChange.value == "zh-cn") {
- return " 老年";
- } else {
- return "Senior";
- }
- }
- }
- // 试听
- const previewAudioUrl = ref(null);
- const previewAudioLoading = ref(false);
- async function getPreviewAudio() {
- previewAudioLoading.value = true;
- if (!textareaContent.value) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `您还没有输入文案`
- : `You have not entered the copy yet`
- );
- previewAudioLoading.value = false;
- return;
- }
- if (!sound.value) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `您还没有选择声音`
- : `You have not selected the sound`
- );
- previewAudioLoading.value = false;
- return;
- }
-
- try {
- const res = await previewAudioApi(
- textareaContent.value,
- sound.value,
- soundStyle.value
- );
- if (!res.data.data) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `暂时无法试听,请稍后重试`
- : `Unable to listen, please try again later`
- );
- previewAudioLoading.value = false;
- return;
- }
- previewAudioUrl.value = res.data.data;
-
- let audioA = document.getElementById("audio");
- audioA.addEventListener("loadedmetadata", async () => {
- audioA.muted = false; // 将 muted 属性设置为 false
- await audioA.play();
- previewAudioLoading.value = false;
- console.log(audioA.muted, "播放了");
- });
- } catch (error) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `暂时无法试听,请稍后重试`
- : `Unable to listen, please try again later`
- );
- previewAudioLoading.value = false;
- return;
- }
- }
- // 新的试听
- function ListenVoices(url) {
- previewAudioUrl.value = url;
- // previewAudioUrl.value =
- // "/suimang/static/tts/2023-07-04/16884538755531874.wav";
- let audioA = document.getElementById("audio");
- audioA.addEventListener("loadedmetadata", async () => {
- audioA.muted = false; // 将 muted 属性设置为 false
- await audioA.play();
- previewAudioLoading.value = false;
- });
- }
- //#endregion
-
- //#region card2的逻辑
- const showAudioWhich = ref(0); // 哪个音乐控件显示
- //#endregion ----------------------------
-
- //#region 录制MP3上传语音
- const parameter = {
- sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
- sampleRate: 8000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
- numChannels: 1, // 声道,支持 1 或 2, 默认是1
- };
- const recorder = new Recorder(parameter);
- const isRecording = ref(true);
- const audioUrl = ref(null); // audio控件的url
- const audioData = ref("");
- const videoId = ref(null); //上传mp3的videoId,创建视频会用到
- const duration = ref(""); //实时显示录音时长
- const getduration = ref(null);
- const startRecording = async () => {
- if (showAudioWhich.value != 2) {
- audioUrl.value = null;
- audioData.value = null;
- showAudioWhich.value = 2;
- }
- try {
- await recorder.start();
- duration.value = 0;
- console.log("Recording started");
- isRecording.value = false;
- getduration.value = setInterval(() => {
- if (isRecording.value == true) {
- clearInterval(getduration.value);
- return;
- }
- if (duration.value >= 60) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `免费用户录音时长限制为60秒!`
- : `Free user recording duration is limited to 60 seconds!`
- );
- clearInterval(getduration.value);
- stopRecording();
- return;
- }
- duration.value = Math.floor(recorder.duration);
- // console.log(duration.value);
- }, 500);
- onUnmounted(() => {
- clearInterval(duration.value);
- });
- } catch (error) {
- console.error(error);
- }
- };
-
- const stopRecording = async () => {
- try {
- const recording = await recorder.stop();
- audioUrl.value = URL.createObjectURL(recorder.getWAVBlob());
- audioData.value = recorder.getWAVBlob();
- isRecording.value = true;
- // console.log(document.getElementById("uploadAudio").duration);
- } catch (error) {
- console.error(error);
- }
- };
-
- const playRecording = () => {
- if (audioUrl.value) {
- const audio = new Audio(audioUrl.value);
- audio.play();
- }
- };
- // 上传音频
- async function uploadAudio(isSaveVideo) {
- createLoading.value = true;
- let formData = new FormData();
- const timestamp = Date.now();
- formData.append("file", audioData.value, timestamp + ".mp3");
- try {
- const res = await videoUpload(formData);
- videoId.value = res.data.videoId;
- if (res) {
- // ElMessage.success("上传成功!");
- } else {
- ElMessage.error(
- lanChange.value == "zh-cn" ? `上传音频失败!` : `Failed to upload audio!`
- );
- return;
- }
- // 查询进度
- intervalId = setInterval(() => {
- uploadProgress(res.data.videoId, isSaveVideo);
- }, 1000);
- // ElMessage.success("上传成功!");
- } catch (error) {
- ElMessage.error(error);
- }
- }
- //#endregion ------------------------------------
-
- //#region 上传音频功能
- const fileInput = ref(null);
-
- let intervalId = null; // 用于存储 setInterval 的返回值
- const uploadAudioTime = ref(null); // 音频时长
- // 点击上传input
- function handleFileClick(e) {
- stopRecording();
- duration.value = 0;
- showAudioWhich.value = 0;
- audioUrl.value = null;
- audioData.value = null;
- e.target.value = null;
- }
- // 上传input触发change
- const handleFileChange = async () => {
- await stopRecording();
- showAudioWhich.value = 1;
- const file = fileInput.value.files[0];
-
- if (file) {
- const videoUrl = URL.createObjectURL(file);
- const audio2 = new Audio();
- audio2.src = videoUrl;
- // 进行大小时长限制
- await countAudioTime(audio2);
- // 限制60秒
- if (uploadAudioTime.value > 60) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `上传音频大小或者长度超出限制,请重新上传`
- : `The size or length of the uploaded audio exceeds the limit. Please upload it again`
- );
- audioUrl.value = null;
- audioData.value = null;
- return;
- }
- // 限制5mb
- if (file.size / 1048576 > 5) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `上传音频大小或者长度超出限制,请重新上传`
- : `The size or length of the uploaded audio exceeds the limit. Please upload it again`
- );
- audioUrl.value = null;
- audioData.value = null;
- return;
- }
- // 成功了
- audioUrl.value = videoUrl;
- audioData.value = file;
- }
- };
- // 计算音频的时长
- const countAudioTime = async (audio) => {
- while (isNaN(audio.duration) || audio.duration === Infinity) {
- // 延迟一会 不然网页都卡死
- await new Promise((resolve) => setTimeout(resolve, 200));
- // 设置随机播放时间,模拟调进度条
- audio.currentTime = 10000000 * Math.random();
- }
- // console.log("音频的总时长:", Math.floor(audio.duration));
- uploadAudioTime.value = Math.floor(audio.duration);
- };
-
- // 获取视频上传进度
- const afterSaveAudioId = ref(null);
- async function uploadProgress(videoId, isSaveVideo) {
- const res = await uploadProgressApi(videoId);
- if (res.data == "complete") {
- clearInterval(intervalId);
- try {
- const res2 = await saveAudioApi({
- videoId: videoId,
- sendType: showAudioWhich.value,
- });
- afterSaveAudioId.value = res2.data.id; // 得到id
- } catch (error) {
- ElMessage.error(error);
- }
- // 定义参数
- const saveOrUpdateData = {
- id: id.value, //从草稿或者重新编辑回到创建视频时有id
- title: title.value,
- personPhotoId: faceItemActive.value, //任务照片id,
- voiceFrom: tabFrom.value, //:声音来源 1:来自选择模板,2:来自用户上传
- paperwork: textareaContent.value, //文案
- speakTypeStr: soundStyle.value, //声音风格
- voiceMouldId: sound.value, //选择声音id voiceFrom=1 时必传
- voiceMaterialId: afterSaveAudioId.value, //上传音频且保存音频后得到的id voiceFrom=2 时必传
- // subtitleEnabled:SubtitlesSwitch.value?1:0 , //字幕开关
- // subtitleParams:{
- // Fontname:SubtitlesFontFamily.value,
- // Fontsize:SubtitlesSize.value,
- // Boxwidth:SubtitlesWidth.value,
- // // Boxheight:Number(SubtitlesSize.value+10),
- // Boxheight:SubtitlesBox.value.style.height,
- // SecondaryColour:SubtitlesColorBGRA.value,
- // Marginl:SubtitlesLeft.value,
- // }
- };
- try {
- const res3 = await saveOrUpdateApi(saveOrUpdateData); // 保存数据
- // 这个if判断是不是仅仅保存视频
- if (isSaveVideo == "saveVideo") {
- ElMessage.success(
- lanChange.value == "zh-cn" ? `已保存为草稿` : `Saved as manuscript`
- );
- createLoading.value = false;
- router.push("/myCreating");
- return;
- }
- ElMessage.success(
- lanChange.value == "zh-cn"
- ? `预计生成的视频时长约为${formatTime(uploadAudioTime.value)}`
- : `The video generated is expected to be approximately${formatTime(
- uploadAudioTime.value
- )} in length`
- );
- const res4 = await createVideoApi({ id: res3.data.id }); // 生成视频
- if (res4.message == "success") {
- ElMessage.success(
- lanChange.value == "zh-cn"
- ? `视频正在生成中,请耐心等待`
- : `The video is being generated, please wait patiently`
- );
- }
- createLoading.value = false;
- router.push("/myCreating");
- } catch (error) {
- ElMessage.error(error);
- createLoading.value = false;
- }
- }
- }
- //#endregion --------------------------------------
-
- //#region 生成视频
- // tab栏切换
- const tabFrom = ref(1);
- const createLoading = ref(false);
- // 上传音频后,得到videoId
- // 保存数据
- async function saveOrUpdate(index, isSaveVideo) {
- if (createLoading.value == true) {
- ElMessage.error(lanChange.value == "zh-cn" ? `正在生成` : `Be generating`);
- return;
- }
- tabFrom.value = index; // 判断是哪一个tab栏内的生成视频按钮
- const saveOrUpdateData = {
- id: id.value, //从草稿或者重新编辑回到创建视频时有id
- title: title.value,
- personPhotoId: faceItemActive.value, //任务照片id,
- voiceFrom: tabFrom.value, //:声音来源 1:来自选择模板,2:来自用户上传
- paperwork: textareaContent.value, //文案
- speakTypeStr: soundStyle.value, //声音风格
- voiceMouldId: sound.value, //选择声音id voiceFrom=1 时必传
- voiceMaterialId: afterSaveAudioId.value, //上传音频且保存音频后得到的id voiceFrom=2 时必传
- musicId: musicItemAction.value, // 选中音乐的id,voiceFrom=3 时必传
- };
- if (index == 1) {
- createLoading.value = true;
- if (!saveOrUpdateData.personPhotoId) {
- ElMessage.error(
- lanChange.value == "zh-cn" ? `请选择图片` : `Please select a picture`
- );
- createLoading.value = false;
- return;
- }
- if (!saveOrUpdateData.paperwork) {
- ElMessage.error(
- lanChange.value == "zh-cn" ? `请输入文案` : `Please enter copy`
- );
- createLoading.value = false;
- return;
- }
- if (!saveOrUpdateData.voiceMouldId) {
- ElMessage.error(
- lanChange.value == "zh-cn" ? `请选择声音` : `Please select sound`
- );
- createLoading.value = false;
- return;
- }
- try {
- // 获取预估时长
- const res4 = await previewAudioApi(
- textareaContent.value,
- sound.value,
- soundStyle.value
- );
- if (res4.data.code != 200) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `视频时长预估失败,无法生成视频,您可以换个声音试试`
- : `Video duration estimation failed, can not generate video, you can try to change the sound`
- );
- createLoading.value = false;
- return;
- }
- if (res4.data.data > 60) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `预计生成的视频时长约为${formatTime(
- res4.data.data
- )},免费用户生成视频时长为60秒,无法生成视频`
- : `The video generated is expected to be about ${formatTime(
- res4.data.data
- )} long, and the free user-generated video is 60 seconds long and cannot be generated`
- );
- createLoading.value = false;
- return;
- }
- ElMessage.success(
- lanChange.value == "zh-cn"
- ? `预计生成的视频时长约为${formatTime(res4.data.data)}`
- : `The video generated is expected to be approximately${formatTime(
- res4.data.data
- )} in length`
- );
- const res2 = await saveOrUpdateApi(saveOrUpdateData); // 保存数据
- if (res2.code == 1002) {
- }
- // 这个if判断是不是仅仅保存视频
- if (isSaveVideo == "saveVideo") {
- ElMessage.success(
- lanChange.value == "zh-cn" ? `已保存为草稿` : `Saved as manuscript`
- );
- createLoading.value = false;
- router.push("/myCreating");
- return;
- }
-
- // 3秒后调用生成视频
- const changeHasNewCreate = setTimeout(async () => {
- const res3 = await createVideoApi({ id: res2.data.id }); // 生成视频
- if (res3.message == "success") {
- ElMessage.success(
- lanChange.value == "zh-cn"
- ? `视频正在生成中,请耐心等待`
- : `The video is being generated, please wait patiently`
- );
- }
- createLoading.value = false;
- router.push("/myCreating");
- }, 3000);
- } catch (error) {
- // ElMessage.error($t(error.message));
- ElMessage.error(error);
- createLoading.value = false;
- }
- }
- if (index == 2) {
- if (!saveOrUpdateData.personPhotoId) {
- ElMessage.error(
- lanChange.value == "zh-cn" ? `请选择图片` : `Please select a picture`
- );
- createLoading.value = false;
- return;
- }
- if (!audioData.value && !afterSaveAudioId.value) {
- console.log(audioData.value);
- console.log(afterSaveAudioId.value);
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `请选择音频文件`
- : `Please select an audio file`
- );
- createLoading.value = false;
- return;
- }
- try {
- const res1 = await uploadAudio(isSaveVideo); // 上传音频
- } catch (error) {
- // ElMessage.error(error);
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `生成失败,请重新选择音频`
- : `Generation failed, please re-select the audio`
- );
- createLoading.value = false;
- }
- }
- if (index == 3) {
- createLoading.value = true;
- try {
- if (!saveOrUpdateData.personPhotoId) {
- ElMessage.error(
- lanChange.value == "zh-cn" ? `请选择图片` : `Please select a picture`
- );
- createLoading.value = false;
- return;
- }
- if (!saveOrUpdateData.musicId) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `请选择音乐文件`
- : `Please select an music file`
- );
- createLoading.value = false;
- return;
- }
- const res1 = await saveOrUpdateApi(saveOrUpdateData); // 保存数据
-
- // 这个if判断是不是仅仅保存视频
- if (isSaveVideo == "saveVideo") {
- ElMessage.success(
- lanChange.value == "zh-cn" ? `已保存为草稿` : `Saved as manuscript`
- );
- createLoading.value = false;
- router.push("/myCreating");
- return;
- }
- console.log("ceshi");
- ElMessage.success(
- lanChange.value == "zh-cn"
- ? `预计生成的视频时长约为${formatTime(estimatedDuration.value)}`
- : `The video generated is expected to be approximately${formatTime(
- estimatedDuration.value
- )} in length`
- );
- const res2 = await createVideoApi({ id: res1.data.id }); // 生成视频
- if (res2.message == "success") {
- ElMessage.success(
- lanChange.value == "zh-cn"
- ? `视频正在生成中,请耐心等待`
- : `The video is being generated, please wait patiently`
- );
- }
- createLoading.value = false;
- router.push("/myCreating");
- } catch (error) {
- if (error) {
- ElMessage.error(error);
- } else {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `生成失败,请稍后重试`
- : `Failed to generate, please try again later`
- );
- }
- createLoading.value = false;
- }
- }
- }
- // 预估时长时把秒转为分
- function formatTime(seconds) {
- const minutes = Math.floor(Math.floor(seconds) / 60);
- const remainingSeconds = Math.floor(seconds) % 60;
- const formattedMinutes = String(minutes).padStart(2, "0");
- const formattedSeconds = String(remainingSeconds).padStart(2, "0");
- return `${formattedMinutes}:${formattedSeconds}`;
- }
- //#endregion ----------------------------
-
- //#region 根据作品id查询作品信息并回显
- const id = ref(null); //作品的id
- async function findById(findId) {
- const res = await findByIdApi(findId);
- id.value = res.data.id;
- title.value = res.data.title; //标题回显
- showAudioWhich.value = res.data.voiceMaterial
- ? res.data.voiceMaterial.sendType
- : null;
- faceItemActive.value = res.data.personPhotoId; //aiface高亮和图片id
- tabFrom.value = res.data.voiceFrom; //输入文案还是上传mp3模式
- textareaContent.value = res.data.paperwork; //文案内容
- afterSaveAudioId.value = res.data.voiceMaterialId; //保存音频后得到的id
- imgUrl.value = res.data.personPhotoUrl; //图片回显
- audioUrl.value = res.data.voiceMaterialUrl; // mp3回显
-
- musicItemAction.value = res.data.musicId; //音乐id回显
- language.value = res.data.voiceInfo ? res.data.voiceInfo.languageId : null;
-
- if (language.value) {
- await chooseType(language.value);
- }
- sound.value = res.data.voiceMouldId; //声音id
- chooseStyle();
- soundStyle.value = res.data.speakTypeStr; //选择风格
- }
- //#endregion ----------------------------
-
- //#region card3
- const musicListSystem = ref([]); //展示系统音乐列表
- const musicListPerson = ref([]); //展示个人音乐列表
- const audioMusicUrl = ref(null); //选中音乐Url回显
- const musicItemAction = ref(null); //选中高亮
- const musicListPageNumSystem = ref(1); //系统音乐页数
- const musicListTotalSystem = ref(null); //系统音乐总条数
- const musicListPageNumPerson = ref(1); //个人音乐页数
- const musicListTotalPerson = ref(null); //个人音乐总条数
- const musicListPageSize = ref(8); //
- const musicTabActive = ref(1); //热门歌曲和个人仓库高亮
- const musicData = ref(null); //上传歌曲的数据
- const fileMusicInput = ref(null); // 上传组件的dom
- const estimatedDuration = ref(""); // card3的生成视频预估时长
- // tab切换
- function musicTabActiveChange(index) {
- if (index == 2) {
- if (!AccessToken) {
- router.push({ path: "/login" });
- return;
- }
- }
- musicTabActive.value = index;
- }
- // 获取系统音乐列表
- async function getmusicListSystem(pageNum, pageSize) {
- try {
- const res = await musicListSystemApi(pageNum, pageSize);
- musicListSystem.value = res.data.list;
- musicListTotalSystem.value = Number(res.data.total);
- } catch (error) {
- console.log(error);
- }
- }
- // 获取个人音乐列表
- async function getmusicListPerson(pageNum, pageSize) {
- try {
- const res = await musicListPersonApi(pageNum, pageSize);
- musicListPerson.value = res.data.list;
- musicListTotalPerson.value = Number(res.data.total);
- } catch (error) {
- console.log(error);
- }
- }
- // 系统页数发生改变
- const musicListPageNumSystemChange = (val) => {
- musicListPageNumSystem.value = val;
- getmusicListSystem(musicListPageNumSystem.value, musicListPageSize.value);
- };
- // 个人页数发生改变
- const musicListPageNumPersonChange = (val) => {
- musicListPageNumPerson.value = val;
- getmusicListPerson(musicListPageNumPerson.value, musicListPageSize.value);
- };
- // 点击选择音乐
- function chooseMusicUrl(item) {
- audioMusicUrl.value = item.url;
- musicItemAction.value = item.id;
- estimatedDuration.value = item.time;
- }
- // 转化秒为分秒
- function handleTime(time) {
- let m = Math.floor(time / 60).toFixed(0);
- let s = (time % 60).toFixed(0);
- if (s < 10) {
- s = "0" + s;
- }
- return m + ":" + s;
- }
- // 点击上传音乐
- // 点击上传input
- function handleFileMusicClick(e) {
- musicData.value = null;
- e.target.value = null;
- }
- // 选择文件上传音乐
- async function uploadMusic() {
- const file = fileMusicInput.value.files[0];
- if (file) {
- musicData.value = file;
- let formData = new FormData();
- formData.append("file", musicData.value, file.name + ".mp3");
- const videoUrl = URL.createObjectURL(file);
- const audio2 = new Audio();
- audio2.src = videoUrl;
- // 进行大小时长限制
- await countAudioTime(audio2);
- // 限制60秒
- if (uploadAudioTime.value > 60) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `上传音频大小或者长度超出限制,请重新上传`
- : `The size or length of the uploaded audio exceeds the limit. Please upload it again`
- );
- return;
- }
- // 限制3mb
- if (file.size / 1048576 > 5) {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `上传音频大小或者长度超出限制,请重新上传`
- : `The size or length of the uploaded audio exceeds the limit. Please upload it again`
- );
- return;
- }
- try {
- const res = await videoUpload(formData);
- if (res) {
- // ElMessage.success("上传成功!");
- } else {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `上传音频失败!`
- : `Failed to upload audio!`
- );
- return;
- }
- // 查询进度
- intervalId = setInterval(async () => {
- const res2 = await uploadProgressApi(res.data.videoId);
- if (res2.data == "complete") {
- clearInterval(intervalId);
- try {
- const res3 = await saveMusicApi({ voiceId: res.data.videoId });
- afterSaveAudioId.value = res2.data.id; // 得到id
- musicListPageNumPerson.value = 1;
- const res4 = await musicListPersonApi(
- musicListPageNumPerson.value,
- musicListPageSize.value
- );
- musicListPerson.value = res4.data.list;
- musicListTotalPerson.value = Number(res4.data.total);
- ElMessage.success(
- lanChange.value == "zh-cn" ? `上传成功!` : `Upload successfully`
- );
- } catch (error) {
- ElMessage.error(error);
- }
- }
- }, 1000);
- } catch (error) {
- ElMessage.error(
- lanChange.value == "zh-cn" ? `上传失败!` : `Upload failure`
- );
- }
- }
- }
- // 删除音乐
- async function deleteMusic(id) {
- const msg =
- lanChange.value == "zh-cn"
- ? `确定要删除这首音乐吗? `
- : `Are you sure to delete this music ? `;
- const notice = lanChange.value == "zh-cn" ? "提示" : "Notice";
- const confirm = lanChange.value == "zh-cn" ? "确定" : "Confirm";
- const cancel = lanChange.value == "zh-cn" ? "取消" : "Cancel";
- ElMessageBox.confirm(msg, notice, {
- confirmButtonText: confirm,
- cancelButtonText: cancel,
- }).then(async () => {
- try {
- const res = await delMusicApi(id);
- getmusicListPerson(musicListPageNumPerson.value, musicListPageSize.value);
- ElMessage.success(
- lanChange.value == "zh-cn" ? `删除成功!` : `Successfully deleted `
- );
- } catch (error) {
- ElMessage.error(
- lanChange.value == "zh-cn" ? `删除失败!` : `Deletion failure `
- );
- }
- });
- }
- //#endregion ----------------------------
-
- //#region card4的逻辑
- const problemContent = ref(null);
- const answerContent = ref("");
- let mySocket = null;
- const sendLoading = ref(false);
- // 没有登录时跳转登录页
- function clickTab4(e) {
- if (e.props.label == "AI生成文本" || e.props.label == "AI Script") {
- if (!AccessToken) {
- router.push({ path: "/login" });
- return;
- }
- }
- }
- // 创建websocket
- function createWS() {
- mySocket = new WebSocket("wss://gptsocket.malls.iformall.com:8010");
- mySocket.onopen = () => {
- console.log("WebSocket 连接成功1");
- sendRequirement();
- };
-
- mySocket.onmessage = (event) => {
- // console.log("接收到 WebSocket 消息2:", event.data);
- if (!event.data) {
- return;
- }
- if (event.data == "___talk_end___") {
- sendLoading.value = false;
- mySocket.close();
- return;
- }
-
- answerContent.value = answerContent.value + event.data;
- };
-
- mySocket.onclose = () => {
- console.log(
- "WebSocket 连接关闭3,关闭代码:",
- event.code,
- "关闭原因:",
- event.reason
- );
- console.log(mySocket.readyState, "链接状态3");
- };
-
- mySocket.onerror = (error) => {
- ElMessage.error(
- lanChange.value == "zh-cn"
- ? `GPT服务器连接失败,请稍后重试!`
- : `GPT Server connection failed, please try again later`
- );
- sendLoading.value = false;
- mySocket.close();
- console.error("WebSocket 错误4:", error);
- };
- }
- // 点击发送需求
- async function sendRequirement() {
- // loading
- sendLoading.value = true;
-
- // 无需求时
- if (!problemContent.value) {
- sendLoading.value = false;
- mySocket.close();
- return;
- }
- const sendMessage = [
- {
- role: "user",
- content: problemContent.value,
- },
- ];
- // 如果处于链接状态
-
- if (mySocket.readyState != WebSocket.OPEN) {
- createWS();
- } else {
- answerContent.value = "";
- mySocket.send(JSON.stringify(sendMessage));
- }
- }
- // 复制到文案
- function copyAnswerContent() {
- textareaContent.value = answerContent.value;
- document.getElementById("tab-0").click();
- }
-
- //#endregion ----------------------------
-
- //#region 字幕部分
- const canvasImgBox = ref(null); // 图片外盒子dom
- const SubtitlesBox = ref(null); // 字幕盒子dom
- const SubtitlesSwitch = ref(false); // 字幕开关
- const SubtitlesWidth = ref(250); // 字幕宽度
- const SubtitlesFontFamily = ref(""); //字幕字体系列
- const SubtitlesTop = ref(400); // 字幕Y轴
- const SubtitlesLeft = ref(100); // 字幕X轴
- const SubtitlesRow = ref(false); // 字幕单双行
- const SubtitlesSize = ref(18); // 字幕字号
- const isRotating = ref(false); //控制是否旋转
- const rotationStartAngle = ref(0); //旋转中间件
- const SubtitlesAngle = ref(20); //旋转度数
- const lastMouseAngle = ref(0);
- const initialRotation = ref(0);
- const SubtitlesColor = ref('rgba(255, 255, 255, 1)'); // 字幕字色
- const SubtitlesColorBGRA = ref(rgbaToBgra(SubtitlesColor.value)); // 字幕字色
- const SubtitlesBgc = ref('rgba(0, 0, 0, 1)'); // 字幕背景色
- const SubtitlesBgcBGRA = ref(rgbaToBgra(SubtitlesBgc.value)); // 字幕背景色
- // 调色板
- const colorList = [
- 'rgba(255, 0, 0, 1)', // 红色
- 'rgba(0, 255, 0, 1)', // 绿色
- 'rgba(0, 0, 255, 1)', // 蓝色
- 'rgba(255, 255, 0, 1)', // 黄色
- 'rgba(0, 0, 0, 1)', // 黑色
- 'rgba(0, 255, 255, 1)', // 青色
- 'rgba(128, 0, 0, 1)', // 深红色
- 'rgba(0, 128, 0, 1)', // 深绿色
- 'rgba(0, 0, 128, 1)', // 深蓝色
- 'rgba(255, 255, 255, 1)', // 白色
- 'rgba(128, 0, 128, 1)', // 深品红色
- 'rgba(0, 128, 128, 1)', // 深青色
- 'rgba(255, 128, 0, 1)', // 橙色
- 'rgba(255, 0, 128, 1)', // 粉红色
- 'rgba(0, 255, 128, 1)', // 中绿色
- 'rgba(128, 255, 0, 1)' // 中黄色
- ];
- const fontFamilyList = [
- {label:"黑体",value:"SimHei"},
- {label:"新细明体",value:"PMingLiU"}, {label:"楷体",value:"KaiTi"}, { label: 'Montserrat', value: 'Montserrat' },
- { label: 'Open Sans', value: 'Open Sans' },
- { label: 'Roboto', value: 'Roboto' },
- { label: 'Lato', value: 'Lato' }
- ];
- const SubtitlesColorShow = ref(false); // 字色调色板开关
- const SubtitlesBgcShow = ref(false); // 背景调色板开关
- const handleSubtitlesColorShow = (e) => {
- e.stopPropagation(); // 阻止事件冒泡
- SubtitlesColorShow.value = true;
- SubtitlesBgcShow.value = false;
- };
- const handleSubtitlesBgcShow = (e) => {
- e.stopPropagation(); // 阻止事件冒泡
- SubtitlesBgcShow.value = true;
- SubtitlesColorShow.value = false;
- };
- const handleClickOutside = () => {
- if(SubtitlesColorShow.value==true) {
- }
- SubtitlesColorShow.value = false;
- if(SubtitlesBgcShow.value==true) {
- }
- SubtitlesBgcShow.value = false;
- };
- onMounted(() => {
- document.addEventListener('click',handleClickOutside);
- });
- function rgbaToBgra(rgba) {
- const regex = /rgba\((\d+),\s*(\d+),\s*(\d+),\s*(\d+(\.\d+)?)\)/;
- const match = regex.exec(rgba);
- if (match) {
- const red = parseInt(match[1]);
- const green = parseInt(match[2]);
- const blue = parseInt(match[3]);
- const alpha = parseFloat(match[4]);
- const b = blue;
- const g = green;
- const r = red;
- const a = Math.round(alpha * 255);
- const bgra = `bgra(${b}, ${g}, ${r}, ${a})`;
- return bgra;
- }
-
- // Return the original value if no match is found
- return rgba;
- }
- watch(
- () => SubtitlesColor,
- (newValue, oldValue) => {
- SubtitlesColorBGRA.value = ref(rgbaToBgra(SubtitlesColor.value)); // 字幕字色
-
- },
- { deep: true }
- );
- watch(
- () => SubtitlesBgc,
- (newValue, oldValue) => {
- SubtitlesBgcBGRA.value = ref(rgbaToBgra(SubtitlesBgc.value)); // 字幕背景色
- },
- { deep: true }
- );
- // 计算属性来计算盒子位置
- const SubtitlesStyle = computed(() => {
- return {
- width: SubtitlesWidth.value + 'px',
- top: SubtitlesTop.value + 'px',
- left: SubtitlesLeft.value + 'px',
- fontSize: SubtitlesSize.value + 'px',
- fontFamily: SubtitlesFontFamily.value,
- color: SubtitlesColor.value,
- backgroundColor: SubtitlesBgc.value,
-
- };
- });
-
- // 拖动盒子
- const handleDrag = (event) => {
- if (isResizing.value) {
- return;
- }
- event.preventDefault();
- const boxElement = canvasImgBox.value;
- const imageElement = SubtitlesBox.value;
- const offsetX = event.clientX - imageElement.offsetLeft;
- const offsetY = event.clientY - imageElement.offsetTop;
-
- const onMouseMove = (event) => {
- const newX = event.clientX - offsetX;
- const newY = event.clientY - offsetY;
- SubtitlesLeft.value = newX;
- SubtitlesTop.value = newY;
- };
-
- const onMouseUp = () => {
- document.removeEventListener('mousemove', onMouseMove);
- document.removeEventListener('mouseup', onMouseUp);
- };
-
- document.addEventListener('mousemove', onMouseMove);
- document.addEventListener('mouseup', onMouseUp);
- };
-
- // 改变盒子宽度
- const isResizing = ref(false);
- const startX = ref(0);
-
- const startResize = (event) => {
- isResizing.value = true;
- startX.value = event.clientX;
- document.addEventListener('mousemove', resizeBox);
- document.addEventListener('mouseup', stopResize);
- };
-
- const stopResize = () => {
- isResizing.value = false;
- document.removeEventListener('mousemove', resizeBox);
- document.removeEventListener('mouseup', stopResize);
- };
-
- const resizeBox = (event) => {
- if (isResizing.value) {
- const deltaX = event.clientX - startX.value;
- SubtitlesWidth.value += deltaX;
- startX.value = event.clientX;
- }
- };
-
- const startResize2 = (event) => {
- isResizing.value = true;
- startX.value = event.clientX;
- document.addEventListener('mousemove', resizeBox2);
- document.addEventListener('mouseup', stopResize2);
- };
-
- const stopResize2 = () => {
- isResizing.value = false;
- document.removeEventListener('mousemove', resizeBox2);
- document.removeEventListener('mouseup', stopResize2);
- };
-
- const resizeBox2 = (event) => {
- if (isResizing.value) {
- const deltaX = startX.value - event.clientX;
- const newLeft = SubtitlesLeft.value - deltaX;
- SubtitlesWidth.value += deltaX;
- SubtitlesLeft.value = newLeft;
- startX.value = event.clientX;
- }
- };
- //旋转盒子 暂时弃用
- const startRotation = (event) => {
- isRotating.value = true;
- isResizing.value = true;
- // document.removeEventListener('mousedown', handleDrag);
- document.addEventListener('mousemove', rotateBox);
- document.addEventListener('mouseup', stopRotation);
- const box9CenterX = event.clientX;
- const box9CenterY = event.clientY;
- const SubtitlesBoxCenterX = SubtitlesBox.value.offsetLeft + SubtitlesBox.value.offsetWidth / 2;
- const SubtitlesBoxCenterY = SubtitlesBox.value.offsetTop + SubtitlesBox.value.offsetHeight / 2;
- rotationStartAngle.value = Math.atan2(box9CenterY - SubtitlesBoxCenterY, box9CenterX - SubtitlesBoxCenterX);
- };
-
- const rotateBox = (event) => {
- if (isRotating.value) {
- const SubtitlesBoxCenterX = SubtitlesBox.value.offsetLeft + SubtitlesBox.value.offsetWidth / 2;
- const SubtitlesBoxCenterY = SubtitlesBox.value.offsetTop + SubtitlesBox.value.offsetHeight / 2;
- const mouseAngle = Math.atan2(event.clientY - SubtitlesBoxCenterY, event.clientX - SubtitlesBoxCenterX);
- SubtitlesAngle.value = (mouseAngle - rotationStartAngle.value);
- SubtitlesBox.value.style.transform = `rotate(${SubtitlesAngle.value}rad)`;
- }
- };
- const stopRotation = () => {
- isRotating.value = false;
- isResizing.value = false;
- document.removeEventListener('mousemove', rotateBox);
- document.removeEventListener('mouseup', stopRotation);
- };
- onBeforeUnmount(() => {
- document.removeEventListener('mousemove', resizeBox);
- document.removeEventListener('mouseup', stopResize);
- document.removeEventListener('mousemove', resizeBox2);
- document.removeEventListener('mouseup', stopResize2);
- document.removeEventListener('mousemove', rotateBox);
- document.removeEventListener('mouseup', stopRotation);
- });
- // 监听字幕显示
- watch(
- () => SubtitlesSwitch,
- async (newValue, oldValue) => {
-
- },
- { deep: true }
- );
- // 监听图片变化
- watch(
- () => imgUrl.value,
- async (newValue, oldValue) => {
- await nextTick()
- // console.log(getComputedStyle(document.getElementById("canvasImg"),null));
- },
- { deep: true }
- );
- //#endregion ----------------------------
-
- //#region
-
- //#endregion ----------------------------
-
- //#region $t在script中的使用
- const {
- appContext: {
- config: { globalProperties },
- },
- } = getCurrentInstance();
-
- const string = "createVideo.typeScript";
- const t = globalProperties.$t(string);
- //#endregion ----------------------------
-
- //#region 页面初始化
- onMounted(async () => {
- getAiFaceList(1, pageSize.value, 1);
- if (AccessToken) {
- getAiFaceUserList(1, pageSize.value, 3);
- await getmusicListPerson(
- musicListPageNumPerson.value,
- musicListPageSize.value
- );
- }
- await voiceTotal();
- if (route.query.id) {
- await findById(route.query.id);
- }
- await getmusicListSystem(
- musicListPageNumSystem.value,
- musicListPageSize.value
- );
-
- musicListSystem.value.forEach((item) => {
- if (item.id == musicItemAction.value) {
- audioMusicUrl.value = item.url;
- }
- });
- musicListPerson.value.forEach((item) => {
- if (item.id == musicItemAction.value) {
- audioMusicUrl.value = item.url;
- }
- });
- createWS(); //创建websocket
-
- });
- //#endregion ----------------------------
-
- //#region 页面销毁
- onUnmounted(() => {
- if (mySocket) {
- mySocket.close();
- }
- });
- //#endregion ----------------------
-
- </script>
-
- <style lang="scss" scoped>
- .page {
- // height: 1000px;
- height: calc(100vh - 80px);
- // padding: 20px 0 0 40px;
- background-color: #fff;
- border-radius: 25px 0 0;
- }
-
- .left {
-
- width: 68%;
- // height: 860px;
- // height: 1000px;
- // max-height: 100%;
- padding: 20px;
- overflow: hidden;
- // overflow-y: scroll;
- height: 100%;
- :deep(.el-input__wrapper) {
- border: none;
- border-bottom: 2px solid #000;
- border-radius: 0;
- box-shadow: none;
- }
- .el-icon.icon-edit {
- width: 35px;
- height: 35px;
- font-size: 35px;
- color: #8c939d;
- text-align: center;
- }
-
- &-top {
- position: relative;
- width: 100%;
- // height: 65%;
- // height: 580px;
- height: 67%;
- // height: calc(70vh - 80px );
- margin-bottom: 20px;
- overflow: hidden;
- .editSubtitlesBox{
- display: flex;
- justify-content: space-evenly;
- // padding-right: 80px;
- padding:0 10px;
- margin-left: 10px;
- margin-right: 80px;
- border-radius: 20px;
- flex: 1;
- line-height: 35px;
- background-color: #f1f2f6;
- font-size: 16px;
- .item {
- display: flex;
- align-items: center;
- margin-left: 10px;
- img {
- cursor: pointer;
- }
- // 调色盘
- .myColorBox {
- position: relative;
- width: 25px;
- height: 25px;
- cursor: pointer;
- .selectColor {
- position: absolute;
- top: 150%;
- left: 50%;
- transform: translateX(-50%);
- display: flex;
- justify-content: flex-start;
- flex-wrap: wrap;
- width: 142px;
- background-color: #ffffff;
- z-index: 99;
- box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 5px 5px;
- &::before {
- content: "";
- display: block;
- position: absolute;
- top: -10%;
- left: 50%;
- transform: translateX(-50%);
- width: 0;
- height: 0;
- border-left: 15px solid transparent;
- border-right: 15px solid transparent;
- border-bottom: 15px solid white;
- }
- &-item {
- width: 25px;
- height: 25px;
- margin: 5px 5px;
- border: #000 solid 2px;
- border-radius: 5px;
- cursor: pointer;
- }
- }
- }
- .el-input {
- width: 60px;
- height: 25px;
- }
- .el-input__wrapper {
- height: 25px;
- }
- }
- :deep(.el-input__wrapper) {
- border: none;
- border: 2px solid #000;
- border-radius: 5px;
- box-shadow: none;
-
- }
- }
- .uploadBtn {
- position: relative;
- padding: 10px 15px;
- margin-left: 10px;
- border-radius: 5px;
- transition: all 0.3s;
- background-color: #000;
- color: #fff;
- &:hover {
- background-color: #15d1b8;
- }
- }
- .bigImg {
- display: flex;
- align-items: center;
- justify-content: space-between;
- width: 50%;
- height: 88%;
- margin-top: 20px;
-
- .SubtitlesBox {
- position: absolute;
- user-select: none;
- // width: 200px;
- padding: 5px 5px;
- text-align: center;
- // border: 2px solid rgba(0, 0, 0, 0);
- border: 2px solid #00ff00;
- background-color: #fff;
- cursor: move;
- &:hover {
- // border: 2px solid #00ff00;
- .stretchBox {
- // opacity: 1;
- }
- }
- .SubtitlesTip {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- .stretchBox {
- opacity: 1;
- position: absolute;
- width: 10px;
- height: 10px;
- background-color: #fff;
-
- }
- .box1 {
- top: -5px;
- left: -5px;
- cursor: nwse-resize;
- display: none;
- }
- .box2 {
- display: none;
- top: -5px;
- left: 50%;
- transform: translateX(-50%);
- cursor: ns-resize;
- }
- .box3 {
- display: none;
- top: -5px;
- left:100%;
- transform: translateX(-5px);
- cursor: nesw-resize;
- }
- .box4 {
- top: 50%;
- left: -5px;
- transform: translateY(-5px);
- cursor: ew-resize;
- }
- .box5 {
- top: 50%;
- left:100%;
- transform: translate(-5px,-5px);
- cursor: ew-resize;
- }
- .box6 {
- display: none;
- top: 100%;
- left: -5px;
- transform: translateY(-5px);
- cursor: nesw-resize;
- }
- .box7 {
- display: none;
- top: 100%;
- left: 50%;
- transform: translate(-5px,-5px);
- cursor: ns-resize;
- }
- .box8 {
- display: none;
- top: 100%;
- left: 100%;
- transform: translate(-5px,-5px);
- cursor: nwse-resize;
- }
- .box9 {
- top: 150%;
- left: 50%;
- transform: translate(-5px,50%);
- cursor: pointer;
- }
- }
- img {
- position: absolute;
- left: 0;
- top: 0;
- max-width: 100%;
- max-height: 100%;
- border-radius: 15px;
- z-index: -1;
- }
- }
-
- .noImg {
- position: relative;
- width: 100%;
- height: 100%;
- border: 1px solid #ccc;
- border-radius: 30px;
- .imgBox {
- position: relative;
- width: 100%;
- height: 100%;
- border-radius: 50%;
- overflow: hidden;
- border: 1px solid #ccc;
- img {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- max-width: 120%;
- }
- }
- .trueImg {
- position: relative;
- top: 4%;
- width: 100px;
- height: 100px;
- border-radius: 50%;
- .icon {
- position: absolute;
- top: 0%;
- right: -5%;
- border: 2px solid #00ff95;
- color: #00ff95;
- }
- }
- .el-upload {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- opacity: 0;
- }
- .upload {
- top: 30%;
- width: 400px;
- height: 200px;
- padding-top: 10px;
- font-size: 50px;
- line-height: 100px;
- text-align: center;
- background-color: rgba(204, 204, 204, 0.1);
- border-radius: 30px;
- box-shadow: rgba(108, 120, 238, 0.3) 0px 0px 5px 5px;
- p {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- z-index: -1;
- opacity: 0.5;
- .el-icon {
- width: 200px;
- height: 200px;
- font-size: 150px;
- }
- img {
- max-width: 60%;
- max-height: 60%;
- }
- }
- span {
- display: block;
- font-size: 16px;
- font-weight: 900;
- line-height: 16px;
- text-align: center;
- margin-bottom: 130px;
- }
- }
-
- .falseImg {
- top: 75%;
- // background-color: #795562;
- display: flex;
- justify-content: space-evenly;
- width: 700px;
- height: 100px;
-
- > div {
- position: relative;
- width: 100px;
- height: 100px;
- background-color: #ccc;
- border-radius: 50%;
- .icon {
- position: absolute;
- top: 0%;
- right: -5%;
- border: 2px solid red;
- color: red;
- }
- }
- }
- }
-
- // 公共类名
- input {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- opacity: 0;
- cursor: pointer;
- }
-
- .icon {
- position: absolute;
- right: 2px;
- width: 30px;
- height: 30px;
- font-size: 20px;
- font-weight: 700;
- line-height: 26px;
- text-align: center;
- border: 2px solid #000;
- border-radius: 50%;
- }
-
- .editAiPicBox {
- position: relative;
- display: flex;
- width: 100%;
- height: 100%;
- border: 1px solid #ccc;
- background-color: #f1f2f6;
- border-radius: 30px;
- overflow: hidden;
- .edit {
- width: 50%;
- height: 100%;
-
- background-color: #fff;
- .TagBox {
- width: 100%;
- height: 100%;
-
- border-radius: 0 0 30px 0;
- background-color: #f1f2f6;
- }
- }
- .AIpicBox {
- position: relative;
- width: 50%;
- height: 100%;
- border-radius: 30px 0 0 0;
- background-color: #fff;
- .picBox {
- position: relative;
- width: 100%;
- height: 100%;
- border-radius: 30px 0 0 0;
- background-color: #fff;
- img {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
-
- max-width: 100%;
- max-height: 100%;
- border-radius: 30px;
- }
- }
- }
- }
- .SubtitlesSwitch {
- position: absolute;
- right: 0;
- top: 0px;
- padding: 10px;
- border-radius: 20px;
- background-color: #f1f2f6;
- text-align: center;
- }
-
-
- }
-
- &-bottom {
- width: 100%;
- height: 29%;
- // height: calc(30vh - 80px );
- // margin-top: 10px;
- .tab {
- padding: 10px;
- > div {
- margin-right: 20px;
- padding: 10px 15px;
- transition: all 0.3s;
- border-radius: 5px;
- &:hover {
- background-color: #000;
- color: #fff;
- }
- }
- .tabAvtive {
- background-color: #000;
- color: #fff;
- }
- }
- .ai {
- width: 100%;
- }
-
- .faceList {
- padding: 8px;
- display: flex;
- flex-wrap: wrap;
- justify-content: flex-start;
- width: 100%;
- // height: 220px;
- height: 90%;
- overflow-y: scroll;
- .faceItem {
- position: relative;
- margin-right: 30px;
- margin-bottom: 35px;
- width: 100px;
- height: 100px;
- // padding: 0 25px;
- line-height: 100px;
- text-align: center;
- border-radius: 50%;
- background-color: #fbf8f8;
- // border: 2px solid #fff;
- box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 5px 5px;
- // overflow: hidden;
- transition: all 0.3s;
- .imgBox {
- cursor: pointer;
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 3;
- width: 100px;
- height: 100px;
- border-radius: 50%;
- background-color: #fbf8f8;
- overflow: hidden;
- img {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- width: 100%;
- }
- }
- .deleteIcon {
- position: absolute;
- top: 0;
- right: -5px;
- z-index: 999;
- width: 25px;
- height: 25px;
- border: 2px solid #6d76ef;
- border-radius: 50%;
- color: #6d76ef;
- font-size: 20px;
- line-height: 23px;
- cursor: pointer;
- }
- .uploadImg {
- line-height: 100px;
- font-size: 50px;
- font-weight: 700;
- text-align: center;
- }
- }
- .faceItemActive {
- position: relative;
- transition: all 0.3s;
- &::before {
- content: "";
- position: absolute;
- // top: -3px;
- // right: -7px;
- // left: -3px;
- // bottom: -7px;
- top: -3px;
- right: -3px;
- left: -3px;
- bottom: -3px;
- z-index: 2;
- border-radius: 50%;
- background: linear-gradient(
- 225deg,
- rgb(81 217 202 / 100%),
- rgb(114 100 245 / 100%)
- );
- }
- }
- }
- .Aipicture {
- width: 100%;
- height: 180px;
- .title {
- font-size: 30px;
- text-align: center;
- line-height: 80px;
- background-image: -webkit-linear-gradient(
- left,
- #4b61dc,
- #15d1b8 25%,
- #4b61dc 50%,
- #15d1b8 75%,
- #4b61dc
- ) !important;
- -webkit-text-fill-color: transparent !important;
- -webkit-background-clip: text !important;
- background-clip: text !important;
- -webkit-background-size: 200% 100% !important;
- background-size: 200% 100% !important;
- .el-icon {
- vertical-align: text-top;
- font-size: 32px;
- }
- }
- }
- .aiPicTab {
- position: relative;
- z-index: 2;
- .subscript {
- position: absolute;
- top: -20px;
- right: -20px;
- width: 40px;
- height: 40px;
- z-index: 3;
- background-color: #fff;
- img {
- position: absolute;
- top: 0;
- left: 0px;
- width: 100%;
- height: 100%;
- z-index: 3;
- }
- span {
- position: absolute;
- line-height: 45px;
- z-index: 4;
- padding-left: 0px;
- padding-bottom: 5px;
- font-size: 16px;
- color: #17ceb9;
- font-weight: 900;
- transform: rotate(45deg);
- }
- }
- .subscript1 {
- position: absolute;
- top: -20px;
- right: -20px;
- width: 40px;
- height: 40px;
- z-index: 3;
- transform: rotate(45deg);
- img {
- position: absolute;
- top: 0;
- left: 0px;
- width: 100%;
- height: 100%;
- z-index: 3;
- }
- span {
- position: absolute;
- line-height: 45px;
- z-index: 4;
- padding-left: 6px;
- padding-bottom: 5px;
- font-size: 16px;
- color: #17ceb9;
- font-weight: 900;
- transform: rotate(45deg);
- }
- }
- }
- }
- }
-
- .right {
- width: 32%;
- // height: 860px;
- // height: 1000px;
- // max-height: 100%;
- padding: 30px 30px 20px 30px;
- background-color: #f1f2f6;
- border-radius: 30px 0 0 0;
- position: relative;
- z-index: 2;
- overflow: hidden;
- overflow-y: scroll;
- height: 100%;
- .subscript {
- position: absolute;
- top: 30px;
- right: 35px;
- width: 40px;
- height: 40px;
- z-index: 3;
- transform: rotate(45deg);
- img {
- position: absolute;
- top: 0;
- left: 0px;
- width: 100%;
- height: 100%;
- z-index: 3;
- }
- span {
- position: absolute;
- line-height: 45px;
- z-index: 4;
- padding-left: 0px;
- padding-bottom: 5px;
- font-size: 16px;
- color: #17ceb9;
- font-weight: 900;
- transform: rotate(45deg);
- }
- }
- :deep(.el-tabs--border-card) {
- font-size: 20px;
- border: none;
- }
-
- .tabs {
- min-height: 100%;
- padding: 20px 20px 0px 20px;
- border-radius: 20px;
- position: relative;
-
- .card1 {
- .text {
- padding: 10px;
- border: 1px solid #c0c4cc;
- .el-button {
- float: right;
- margin-top: 10px;
- }
-
- :deep(.el-textarea__inner) {
- resize: none;
- box-shadow: none;
- }
- }
-
- p {
- margin: 7px 0;
- }
-
- > .el-button {
- width: 100%;
- height: 50px;
- margin-top: 10px;
- }
- .sundriesBox {
- width: 100%;
- height: 30px;
- line-height: 30px;
- overflow: hidden;
- span {
- display: inline-block;
- font-size: 20px;
- height: 30px;
- width: 30px;
- text-align: center;
- width: 40px;
- }
- i {
- font-size: 14px;
- float: right;
- }
- .previewAudioLoadingBox {
- display: inline-block;
- margin-top: -20px;
- width: 20px;
- height: 33px;
- transform: scale(1);
- transition: all 0.3s;
- }
- }
- :deep(.el-input .is-focus) {
- // box-shadow: none !important;
- // box-shadow: 0 0 0 1px #000 !important;
- }
- }
- .card2 {
- .overtimeTips {
- height: 0;
- opacity: 0;
- font-size: 16px;
-
- // width: 60%;
- // display: inline-block;
- padding: 5px;
- margin-bottom: 10px;
- // background-color: #ccc;
- border-radius: 5px;
- line-height: 20px;
- color: red;
- text-align: center;
- img {
- width: 16px;
- height: 16px;
- vertical-align: text-top;
- margin-right: 5px;
- }
- border: none;
- box-shadow: none;
- &:hover {
- transform: translateY(0);
- }
- }
- padding: 10px;
- .el-icon {
- flex: 1;
- // color: red;
- vertical-align: text-top;
- transition: all 0.3s;
- }
- > div {
- position: relative;
- margin-top: 10px;
- width: 100%;
- border: #000 1px solid;
- border-radius: 10px;
- overflow: hidden;
- transition: all 0.3s;
- box-shadow: #00000026 2px 2px 2px 2px;
- &:hover {
- transform: translateY(-10px);
- }
- }
- // 录制mp3部分
- .uploadAudio {
- padding: 20px;
- // margin-top: 30px;
- margin-bottom: 20px;
- // height: 70px;
- .btnBox {
- display: flex;
- justify-content: space-between;
- // justify-content: flex-end;
- margin-bottom: 10px;
- }
- audio {
- height: 50px;
- width: 100%;
- }
- button {
- border-radius: 10px;
- // height: 30px;
- line-height: 22px;
- padding: 5px 10px;
- background-color: #fff;
- transition: all 0.3s;
- cursor: pointer;
- &:hover {
- background-color: #000;
-
- color: #fff;
- }
- .el-icon {
- font-size: 20px;
- }
- }
- }
- .uploadAudioAvtion {
- height: 170px;
- }
- .uploadAudioAvtion2 {
- // height: 220px !important;
- }
- // 上传音频部分
- .uploadVideo {
- display: flex;
- justify-content: space-between;
- align-items: center;
- text-align: center;
- margin-bottom: 20px;
- height: 100px;
- font-size: 50px;
- font-weight: 700;
- line-height: 100px;
- transition: all 0.3s;
- img {
- margin: auto;
- max-width: 80%;
- max-height: 80%;
- }
- input {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100px;
- opacity: 0;
- cursor: pointer;
- }
- }
- .AudioBox {
- display: flex;
- justify-content: space-around;
- padding: 10px;
- transition: all 0.3s;
- }
- > .el-button {
- width: 100%;
- height: 50px;
- margin-top: 10px;
- // background-color: #000;
- }
- }
- .card3 {
- width: 100%;
- padding: 10px;
- .overtimeTips {
- opacity: 0;
- height: 0;
- font-size: 16px;
- // width: 60%;
- // display: inline-block;
- padding: 5px;
- margin-bottom: 10px;
- // background-color: #ccc;
- border-radius: 5px;
- line-height: 20px;
- color: red;
- text-align: center;
- img {
- width: 16px;
- height: 16px;
- vertical-align: text-top;
- margin-right: 5px;
- }
- border: none;
- box-shadow: none;
- }
- .el-icon {
- vertical-align: text-top;
- }
- .musicTab {
- display: flex;
- width: 100%;
- height: 50px;
- line-height: 50px;
- text-align: center;
- .musicTabItem {
- background-color: #f5f7fa;
- width: 50%;
- cursor: pointer;
- }
- .musicTabItemActive {
- background-color: #000;
- color: #fff;
- }
- }
- .uploadVideo {
- position: relative;
- margin-top: 10px;
- width: 100%;
- border: #000 1px solid;
- border-radius: 10px;
- overflow: hidden;
- transition: all 0.3s;
- box-shadow: #00000026 2px 2px 2px 2px;
-
- text-align: center;
- margin-bottom: 20px;
- height: 100px;
- font-size: 50px;
- font-weight: 700;
- line-height: 100px;
- input {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- opacity: 0;
- cursor: pointer;
- }
- }
- .musicList {
- width: 100%;
- display: flex;
- flex-wrap: wrap;
- justify-content: space-between;
- .musicItem {
- width: 100%;
- height: 30px;
- position: relative;
- margin-top: 10px;
- padding: 0 20px;
- border: #000 1px solid;
- border-radius: 10px;
- overflow: hidden;
- transition: all 0.3s;
- box-shadow: #00000026 2px 2px 2px 2px;
- transition: all 0.3s;
- cursor: pointer;
- .musicNmae {
- display: inline-block;
- width: 260px;
- margin-right: 20px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .musicTime {
- display: inline-block;
- max-width: 300px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .delMusic {
- color: #fff;
- padding-left: 15px;
- padding-top: -15px;
- line-height: 30px;
- vertical-align: top;
- }
- }
- .musicItemAvtive {
- background-color: #000;
- color: #fff;
- }
- }
- .pagination {
- // position: fixed;
- // bottom: 20px;
- // left: 50%;
- // transform: translateX(-50%);
- margin-top: 10px;
- background-color: #ffffff;
- padding: 10px 20px;
- border-radius: 8px;
- transition: all 0.3s;
- cursor: pointer;
- &:hover {
- background-color: #b8b8b873;
- }
- }
- .AudioBox {
- display: flex;
- justify-content: space-around;
- width: 100%;
- padding: 20px;
- transition: all 0.3s;
- audio {
- width: 100%;
- }
- }
- > .el-button {
- width: 100%;
- height: 50px;
- margin-top: 10px;
- }
- :deep(.el-input__wrapper) {
- border: none;
- border-bottom: 2px solid #000;
- border-radius: 0;
- box-shadow: none;
- }
-
- .el-icon.icon-edit {
- width: 30px;
- height: 30px;
- font-size: 30px;
- color: #8c939d;
- text-align: center;
- cursor: pointer;
- transition: all 0.3s;
- &:hover {
- color: #292929;
- }
- }
- }
- .card4 {
- .text {
- padding: 10 px;
- border: 1px solid #c0c4cc;
- .el-button {
- float: right;
- margin-top: 10px;
- }
- :deep(.el-textarea__inner) {
- cursor: text;
- }
- :deep(.el-textarea__inner) {
- resize: none;
- box-shadow: none;
- }
- i {
- font-size: 14px;
- float: right;
- }
- }
-
- p {
- margin: 7px 0;
- }
- .card4Btn {
- margin-top: 10px;
- border-radius: 5px;
- height: 50px;
- width: 100%;
- color: #fff;
- background-color: #000;
- text-align: center;
- line-height: 50px;
- cursor: pointer;
- }
- .el-button {
- width: 100%;
- height: 50px;
- margin-top: 10px;
- }
- }
- :deep(.el-tabs__item.is-active) {
- color: #909393;
- background-color: #000;
- }
-
- :deep(.el-tabs__nav) {
- width: 100%;
- }
-
- :deep(.el-tabs__item) {
- width: 26%;
- }
-
- :deep(.el-tabs__item:hover) {
- color: #909393;
- }
-
- :deep(.el-tabs__content) {
- height: calc(100% - 60px);
- padding: 0;
- }
- }
- }
- </style>
|