|
|
@@ -4,7 +4,7 @@ |
|
|
|
<div class="left"> |
|
|
|
<!-- 顶部 --> |
|
|
|
<!-- 有图片时 --> |
|
|
|
<div class="left-top" v-show="imgUrl"> |
|
|
|
<div class="left-top" v-show="!showUploadBtn"> |
|
|
|
<el-row class="justify-between"> |
|
|
|
<!-- title框 --> |
|
|
|
<div class="flex justify-between" style="width: 300px"> |
|
|
@@ -15,10 +15,15 @@ |
|
|
|
<el-icon class="icon-edit"><i-ep-edit /></el-icon> |
|
|
|
</div> |
|
|
|
<!-- 上传按钮 --> |
|
|
|
<div class="btnBox"> |
|
|
|
<div class="btnBox" v-show="submitImgBtn"> |
|
|
|
<button class="uploadBtn"> |
|
|
|
{{ $t("createVideo.reselect") }} |
|
|
|
<input type="file" @change="lookImg" /> |
|
|
|
<input |
|
|
|
accept="image/*" |
|
|
|
type="file" |
|
|
|
@click="e.target.value = null" |
|
|
|
@change="lookImg" |
|
|
|
/> |
|
|
|
</button> |
|
|
|
<button class="uploadBtn" @click="changeFile"> |
|
|
|
{{ $t("createVideo.sureUpload") }} |
|
|
@@ -31,27 +36,26 @@ |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<!-- 没有图片时 --> |
|
|
|
<div class="left-top" v-show="!imgUrl"> |
|
|
|
<div class="left-top" v-show="showUploadBtn"> |
|
|
|
<!-- 中间展示大图 --> |
|
|
|
<div class="noImg"> |
|
|
|
<div class="trueImg inmiddle"> |
|
|
|
<my-loading |
|
|
|
style="margin-top: 150px" |
|
|
|
:isLoading="compressionImgLoad" |
|
|
|
></my-loading> |
|
|
|
<div v-if="!compressionImgLoad" class="trueImg inmiddle"> |
|
|
|
<div class="icon">✔</div> |
|
|
|
</div> |
|
|
|
<div class="upload inmiddle"> |
|
|
|
<div v-if="!compressionImgLoad" class="upload inmiddle"> |
|
|
|
+ |
|
|
|
<input type="file" @change="lookImg" /> |
|
|
|
<!-- <el-upload |
|
|
|
class="el-upload" |
|
|
|
v-model="fileList" |
|
|
|
multiple |
|
|
|
:on-preview="handlePreview" |
|
|
|
:on-remove="handleRemove" |
|
|
|
:before-remove="beforeRemove" |
|
|
|
:limit="3" |
|
|
|
:on-exceed="handleExceed" |
|
|
|
/> --> |
|
|
|
<input |
|
|
|
accept="image/*" |
|
|
|
type="file" |
|
|
|
@click="e.target.value = null" |
|
|
|
@change="lookImg" |
|
|
|
/> |
|
|
|
</div> |
|
|
|
<div class="falseImg inmiddle"> |
|
|
|
<div v-if="!compressionImgLoad" class="falseImg inmiddle"> |
|
|
|
<div><div class="icon">×</div></div> |
|
|
|
<div><div class="icon">×</div></div> |
|
|
|
<div><div class="icon">×</div></div> |
|
|
@@ -79,23 +83,26 @@ |
|
|
|
</div> |
|
|
|
<div class="faceList"> |
|
|
|
<!-- 上传图片组件 --> |
|
|
|
<div v-if="showFace == 1" class="faceItem"> |
|
|
|
<span class="uploadImg" |
|
|
|
>+ |
|
|
|
<input class="pointer" type="file" @change="lookImg" /> |
|
|
|
</span> |
|
|
|
<div |
|
|
|
v-if="showFace == 1" |
|
|
|
class="faceItem" |
|
|
|
@click="showUploadBtn = true" |
|
|
|
> |
|
|
|
<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)" |
|
|
|
@click="setImgUrl(item.material, item.id)" |
|
|
|
v-for="item in AiFaceList" |
|
|
|
:key="item.id" |
|
|
|
> |
|
|
|
<!-- <div class="img"></div> --> |
|
|
|
<img :src="item.material" alt="" /> |
|
|
|
<p>{{ item.title }}</p> |
|
|
|
<div class="imgBox"> |
|
|
|
<img :src="item.material" alt="" /> |
|
|
|
</div> |
|
|
|
s |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
@@ -114,18 +121,26 @@ |
|
|
|
<el-button type="primary"> |
|
|
|
{{ $t("createVideo.confirm") }} |
|
|
|
</el-button> |
|
|
|
<!-- 文本域 --> |
|
|
|
<el-input |
|
|
|
v-model="title" |
|
|
|
id="textInputId" |
|
|
|
v-model="textareaContent" |
|
|
|
:rows="15" |
|
|
|
type="textarea" |
|
|
|
:placeholder="$t('createVideo.aiText')" |
|
|
|
/> |
|
|
|
<el-icon :size="20"> |
|
|
|
<Edit /> |
|
|
|
</el-icon> |
|
|
|
<span |
|
|
|
class="pointer" |
|
|
|
@click="getPreviewAudio" |
|
|
|
style="margin-right: 10px; font-size: 30px" |
|
|
|
>🕬</span |
|
|
|
> |
|
|
|
<span class="pointer" @click="insertIcon">🕗</span> |
|
|
|
</div> |
|
|
|
<p>{{ $t("createVideo.languages") }}</p> |
|
|
|
<!-- 语言 --> |
|
|
|
<el-select |
|
|
|
@change="chooseType" |
|
|
|
v-model="language" |
|
|
|
placeholder="Select" |
|
|
|
style="width: 100%" |
|
|
@@ -133,45 +148,90 @@ |
|
|
|
<el-option |
|
|
|
v-for="item in languageOptions" |
|
|
|
:key="item.value" |
|
|
|
:label="item.label" |
|
|
|
:value="item.value" |
|
|
|
/> |
|
|
|
:label="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">{{ item.name }}</span> |
|
|
|
</el-option> |
|
|
|
</el-select> |
|
|
|
<p>{{ $t("createVideo.voices") }}</p> |
|
|
|
<!-- 声音 --> |
|
|
|
<el-select |
|
|
|
v-model="language" |
|
|
|
placeholder="Select" |
|
|
|
@change="chooseStyle" |
|
|
|
:disabled="language ? false : true" |
|
|
|
v-model="sound" |
|
|
|
:placeholder="language ? 'Select' : 'Please select language'" |
|
|
|
style="width: 100%" |
|
|
|
> |
|
|
|
<el-option |
|
|
|
v-for="item in languageOptions" |
|
|
|
v-for="item in soundOptions" |
|
|
|
:key="item.value" |
|
|
|
:label="item.label" |
|
|
|
:value="item.value" |
|
|
|
:label="item.displayName" |
|
|
|
:value="item.id" |
|
|
|
/> |
|
|
|
</el-select> |
|
|
|
<p>{{ $t("createVideo.styles") }}</p> |
|
|
|
<!-- 风格 --> |
|
|
|
<el-select |
|
|
|
v-model="language" |
|
|
|
placeholder="Select" |
|
|
|
:disabled="soundStyleOptions ? false : true" |
|
|
|
v-model="soundStyle" |
|
|
|
:placeholder="soundStyleOptions ? 'Select' : '暂无数据'" |
|
|
|
style="width: 100%" |
|
|
|
> |
|
|
|
<el-option |
|
|
|
v-for="item in languageOptions" |
|
|
|
:key="item.value" |
|
|
|
:label="item.label" |
|
|
|
:value="item.value" |
|
|
|
v-for="item in soundStyleOptions" |
|
|
|
:key="item" |
|
|
|
:label="item" |
|
|
|
:value="item" |
|
|
|
/> |
|
|
|
</el-select> |
|
|
|
<el-button type="primary">{{ |
|
|
|
$t("createVideo.generateVideo") |
|
|
|
}}</el-button> |
|
|
|
<el-button @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-VideoCamera"><i-ep-VideoCamera /></el-icon> |
|
|
|
上传音频 |
|
|
|
</p> |
|
|
|
<div class="uploadVideo"> |
|
|
|
+ |
|
|
|
<input |
|
|
|
accept="audio/*" |
|
|
|
type="file" |
|
|
|
ref="fileInput" |
|
|
|
@click="e.target.value = null" |
|
|
|
@change="handleFileChange" |
|
|
|
/> |
|
|
|
<!-- <video |
|
|
|
style="position: absolute; top: 0" |
|
|
|
v-if="videoSrc" |
|
|
|
:src="videoSrc" |
|
|
|
ref="videoPlayer" |
|
|
|
controls |
|
|
|
></video> --> |
|
|
|
</div> |
|
|
|
<!-- 录制MP3上传语音 --> |
|
|
|
<p> |
|
|
|
<el-icon class="icon-Mic"><i-ep-Mic /></el-icon> |
|
|
|
录制音频 |
|
|
|
</p> |
|
|
|
<div |
|
|
|
class="uploadAudio" |
|
|
|
:class="audioUrl ? 'uploadAudioAvtion' : ''" |
|
|
@@ -194,24 +254,16 @@ |
|
|
|
</div> |
|
|
|
<!-- <button @click="playRecording">播放录音</button> --> |
|
|
|
<audio v-if="audioUrl" controls :src="audioUrl"></audio> |
|
|
|
<button v-if="audioUrl" @click="uploadAudio" class="pointer"> |
|
|
|
<!-- <button v-if="audioUrl" @click="uploadAudio" class="pointer"> |
|
|
|
上传音频 |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
<!-- 上传视频 --> |
|
|
|
<div |
|
|
|
class="uploadVideo" |
|
|
|
style="text-align: center; line-height: 70px" |
|
|
|
> |
|
|
|
上传视频 |
|
|
|
<input type="file" ref="fileInput" @change="handleFileChange" /> |
|
|
|
<video |
|
|
|
v-if="videoSrc" |
|
|
|
:src="videoSrc" |
|
|
|
ref="videoPlayer" |
|
|
|
controls |
|
|
|
></video> |
|
|
|
</button> --> |
|
|
|
</div> |
|
|
|
<el-button @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 --> |
|
|
@@ -281,25 +333,38 @@ |
|
|
|
</el-tab-pane> |
|
|
|
</el-tabs> |
|
|
|
</div> |
|
|
|
<!-- 试听的mp3 --> |
|
|
|
<div style="opacity: 0; width: 0"> |
|
|
|
<audio autoplay :src="previewAudioUrl"></audio> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script setup> |
|
|
|
import { getCurrentInstance } from "vue"; |
|
|
|
import Recorder from "js-audio-recorder"; |
|
|
|
import { |
|
|
|
personPhotoList, |
|
|
|
awsImgUpload, |
|
|
|
videoUpload, |
|
|
|
saveImgApi, |
|
|
|
uploadProgressApi, |
|
|
|
saveAudioApi, |
|
|
|
voiceTotalApi, |
|
|
|
chooseTypeApi, |
|
|
|
saveOrUpdateApi, |
|
|
|
createVideoApi, |
|
|
|
previewAudioApi, |
|
|
|
} from "@/apis/createVideo"; |
|
|
|
import Recorder from "js-audio-recorder"; //mp3插件 |
|
|
|
import imageCompression from "browser-image-compression"; //压缩图片插件 |
|
|
|
|
|
|
|
//#region 头像区的逻辑 |
|
|
|
// 获取AI头像 |
|
|
|
const AiFaceList = ref([]); |
|
|
|
const feceItemLoading = ref(false); |
|
|
|
function getAiFaceList(pageNum, pageSize) { |
|
|
|
function getAiFaceList(pageNum, pageSize, sendType) { |
|
|
|
feceItemLoading.value = true; |
|
|
|
personPhotoList(pageNum, pageSize) |
|
|
|
personPhotoList(pageNum, pageSize, sendType) |
|
|
|
.then((res) => { |
|
|
|
AiFaceList.value = res.data.list; |
|
|
|
feceItemLoading.value = false; |
|
|
@@ -312,20 +377,51 @@ function getAiFaceList(pageNum, pageSize) { |
|
|
|
// 选择显示的face列表 |
|
|
|
const showFace = ref("0"); |
|
|
|
function ChangeShowFaceList(index) { |
|
|
|
AiFaceList.value = null; |
|
|
|
if (index == 0) { |
|
|
|
getAiFaceList(1, 100, 1); |
|
|
|
} |
|
|
|
if (index == 1) { |
|
|
|
getAiFaceList(1, 100, 3); |
|
|
|
} |
|
|
|
showFace.value = index; |
|
|
|
} |
|
|
|
const faceItemActive = ref(); //高亮处理和当前选择图片的ID |
|
|
|
// 点击aifece |
|
|
|
function setImgUrl(url, id) { |
|
|
|
faceItemActive.value = id; |
|
|
|
showUploadBtn.value = false; |
|
|
|
submitImgBtn.value = false; |
|
|
|
imgUrl.value = url; |
|
|
|
} |
|
|
|
//#endregion ------------------------------ |
|
|
|
|
|
|
|
//#region 预览图片 |
|
|
|
const compressionImgLoad = ref(false); |
|
|
|
async function lookImg(e) { |
|
|
|
// 压缩配置 |
|
|
|
compressionImgLoad.value = true; |
|
|
|
const options = { |
|
|
|
maxSizeMB: 2, // 最大压缩大小为 1MB |
|
|
|
useWebWorker: true, // 使用 Web Worker 进行压缩,提高性能 |
|
|
|
}; |
|
|
|
const compressedFile = await imageCompression(e.target.files[0], options); |
|
|
|
imgUrl.value = URL.createObjectURL(compressedFile); |
|
|
|
imgData.value = compressedFile; |
|
|
|
showUploadBtn.value = false; |
|
|
|
submitImgBtn.value = true; |
|
|
|
compressionImgLoad.value = false; |
|
|
|
} |
|
|
|
//#endregion ------------------ |
|
|
|
|
|
|
|
// 标题 |
|
|
|
const title = ref(""); |
|
|
|
|
|
|
|
// 上传图片 |
|
|
|
const imgUrl = ref(""); |
|
|
|
const imgData = ref(""); |
|
|
|
const showUploadBtn = ref(false); |
|
|
|
// 预览图片 |
|
|
|
function lookImg(e) { |
|
|
|
imgUrl.value = URL.createObjectURL(e.target.files[0]); |
|
|
|
imgData.value = e.target.files[0]; |
|
|
|
} |
|
|
|
//#region 上传图片 |
|
|
|
const imgUrl = ref(""); //图片回显路径 |
|
|
|
const imgData = ref(""); // 上传图片文件 |
|
|
|
const showUploadBtn = ref(false); //上传图片+号的显示隐藏 |
|
|
|
const submitImgBtn = ref(false); //右上角俩按钮显示与隐藏 |
|
|
|
// 上传图片 |
|
|
|
async function changeFile() { |
|
|
|
imgUrl.value = URL.createObjectURL(imgData.value); |
|
|
@@ -344,13 +440,92 @@ async function changeFile() { |
|
|
|
ElMessage.error(error); |
|
|
|
} |
|
|
|
} |
|
|
|
//#endregion --------------------------- |
|
|
|
|
|
|
|
// 点击aifece |
|
|
|
function setImgUrl(url) { |
|
|
|
imgUrl.value = url; |
|
|
|
//#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([ |
|
|
|
{ |
|
|
|
id: "0", |
|
|
|
name: "中文", |
|
|
|
}, |
|
|
|
{ |
|
|
|
id: "1", |
|
|
|
name: "English", |
|
|
|
}, |
|
|
|
]); |
|
|
|
async function voiceTotal() { |
|
|
|
const res = await voiceTotalApi(); |
|
|
|
languageOptions.value = res.data; |
|
|
|
} |
|
|
|
// 声音下拉框内容 |
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
// 录制MP3上传语音 |
|
|
|
// 试听 |
|
|
|
const previewAudioUrl = ref(null); |
|
|
|
async function getPreviewAudio() { |
|
|
|
if (!textareaContent.value) { |
|
|
|
ElMessage.error("您还没有输入文案"); |
|
|
|
return; |
|
|
|
} |
|
|
|
if (!sound.value) { |
|
|
|
ElMessage.error("您还没有选择声音"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
const res = await previewAudioApi( |
|
|
|
textareaContent.value, |
|
|
|
sound.value, |
|
|
|
soundStyle.value |
|
|
|
); |
|
|
|
previewAudioUrl.value = res.data.data; |
|
|
|
console.log(previewAudioUrl.value); |
|
|
|
} catch (error) { |
|
|
|
ElMessage.error(error); |
|
|
|
} |
|
|
|
} |
|
|
|
//#endregion |
|
|
|
|
|
|
|
//#region 录制MP3上传语音 |
|
|
|
const parameter = { |
|
|
|
sampleBits: 16, // 采样位数,支持 8 或 16,默认是16 |
|
|
|
sampleRate: 8000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000 |
|
|
@@ -358,8 +533,9 @@ const parameter = { |
|
|
|
}; |
|
|
|
const recorder = new Recorder(parameter); |
|
|
|
const isRecording = ref(true); |
|
|
|
const audioUrl = ref(null); |
|
|
|
const audioUrl = ref(null); // audio控件的url |
|
|
|
const audioData = ref(""); |
|
|
|
const videoId = ref(null); //上传mp3的videoId,创建视频会用到 |
|
|
|
|
|
|
|
const startRecording = async () => { |
|
|
|
try { |
|
|
@@ -388,42 +564,127 @@ const playRecording = () => { |
|
|
|
audio.play(); |
|
|
|
} |
|
|
|
}; |
|
|
|
async function uploadAudio(params) { |
|
|
|
// 上传音频 |
|
|
|
async function uploadAudio() { |
|
|
|
createLoading.value = true; |
|
|
|
let formData = new FormData(); |
|
|
|
const timestamp = Date.now(); |
|
|
|
formData.append("file", audioData.value, timestamp + ".mp3"); |
|
|
|
try { |
|
|
|
const res = await videoUpload(formData); |
|
|
|
ElMessage.success("上传成功!"); |
|
|
|
videoId.value = res.data.videoId; |
|
|
|
if (res) { |
|
|
|
// ElMessage.success("上传成功!"); |
|
|
|
} else { |
|
|
|
ElMessage.error("音频上传失败!"); |
|
|
|
return; |
|
|
|
} |
|
|
|
// 查询进度 |
|
|
|
intervalId = setInterval(() => { |
|
|
|
uploadProgress(res.data.videoId); |
|
|
|
}, 1000); |
|
|
|
// ElMessage.success("上传成功!"); |
|
|
|
} catch (error) { |
|
|
|
ElMessage.error(error); |
|
|
|
} |
|
|
|
} |
|
|
|
//#endregion ------------------------------------ |
|
|
|
|
|
|
|
// 上传视频功能 |
|
|
|
//#region 上传音频功能 |
|
|
|
const fileInput = ref(null); |
|
|
|
const videoSrc = ref(null); |
|
|
|
const handleFileChange = () => { |
|
|
|
|
|
|
|
let intervalId = null; // 用于存储 setInterval 的返回值 |
|
|
|
const handleFileChange = async () => { |
|
|
|
const file = fileInput.value.files[0]; |
|
|
|
if (file) { |
|
|
|
const videoUrl = URL.createObjectURL(file); |
|
|
|
videoSrc.value = videoUrl; |
|
|
|
audioUrl.value = videoUrl; |
|
|
|
audioData.value = file; |
|
|
|
} |
|
|
|
}; |
|
|
|
// 获取视频上传进度 |
|
|
|
const afterSaveAudioId = ref(null); |
|
|
|
async function uploadProgress(videoId) { |
|
|
|
const res = await uploadProgressApi(videoId); |
|
|
|
if (res.data == "complete") { |
|
|
|
clearInterval(intervalId); |
|
|
|
try { |
|
|
|
const res2 = await saveAudioApi({ videoId: videoId }); |
|
|
|
afterSaveAudioId.value = res2.data.id; // 得到id |
|
|
|
} catch (error) { |
|
|
|
ElMessage.error(error); |
|
|
|
} |
|
|
|
// 定义参数 |
|
|
|
const saveOrUpdateData = { |
|
|
|
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 时必传 |
|
|
|
}; |
|
|
|
try { |
|
|
|
const res3 = await saveOrUpdateApi(saveOrUpdateData); // 保存数据 |
|
|
|
const res4 = await createVideoApi({ id: res3.data.id }); // 生成视频 |
|
|
|
if (res4.message == "success") { |
|
|
|
ElMessage.success("视频正在生成,请耐心等待"); |
|
|
|
} |
|
|
|
createLoading.value = false; |
|
|
|
} catch (error) { |
|
|
|
ElMessage.error(error); |
|
|
|
createLoading.value = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
//#endregion -------------------------------------- |
|
|
|
|
|
|
|
// card3的 |
|
|
|
let language = ref(""); |
|
|
|
//#region 生成视频 |
|
|
|
// tab栏切换 |
|
|
|
const tabFrom = ref(1); |
|
|
|
const createLoading = ref(false); |
|
|
|
// 上传音频后,得到videoId |
|
|
|
// 保存数据 |
|
|
|
async function saveOrUpdate(index) { |
|
|
|
if (createLoading.value == true) { |
|
|
|
return; |
|
|
|
} |
|
|
|
tabFrom.value = index; |
|
|
|
const saveOrUpdateData = { |
|
|
|
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 时必传 |
|
|
|
}; |
|
|
|
if (index == 1) { |
|
|
|
createLoading.value = true; |
|
|
|
try { |
|
|
|
const res2 = await saveOrUpdateApi(saveOrUpdateData); // 保存数据 |
|
|
|
const res3 = await createVideoApi({ id: res2.data.id }); // 生成视频 |
|
|
|
if (res3.message == "success") { |
|
|
|
ElMessage.success("视频正在生成,请耐心等待"); |
|
|
|
} |
|
|
|
createLoading.value = false; |
|
|
|
} catch (error) { |
|
|
|
ElMessage.error(error); |
|
|
|
createLoading.value = false; |
|
|
|
} |
|
|
|
} |
|
|
|
if (index == 2) { |
|
|
|
try { |
|
|
|
const res1 = await uploadAudio(); // 上传音频 |
|
|
|
} catch (error) { |
|
|
|
ElMessage.error(error); |
|
|
|
createLoading.value = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
//#endregion ---------------------------- |
|
|
|
|
|
|
|
let languageOptions = reactive([ |
|
|
|
{ |
|
|
|
value: "Option1", |
|
|
|
label: "Option1", |
|
|
|
}, |
|
|
|
{ |
|
|
|
value: "Option2", |
|
|
|
label: "Option2", |
|
|
|
}, |
|
|
|
]); |
|
|
|
//#region |
|
|
|
|
|
|
|
//#endregion ---------------------------- |
|
|
|
|
|
|
|
// $t在script中的使用 |
|
|
|
const { |
|
|
@@ -436,7 +697,9 @@ const string = "createVideo.typeScript"; |
|
|
|
const t = globalProperties.$t(string); |
|
|
|
|
|
|
|
onMounted(() => { |
|
|
|
getAiFaceList(1, 100); |
|
|
|
getAiFaceList(1, 100, 1); |
|
|
|
voiceTotal(); |
|
|
|
chooseType(); |
|
|
|
}); |
|
|
|
</script> |
|
|
|
|
|
|
@@ -472,7 +735,7 @@ onMounted(() => { |
|
|
|
position: relative; |
|
|
|
width: 100%; |
|
|
|
// height: 65%; |
|
|
|
height: 600px; |
|
|
|
height: 580px; |
|
|
|
|
|
|
|
.uploadBtn { |
|
|
|
position: relative; |
|
|
@@ -600,31 +863,48 @@ onMounted(() => { |
|
|
|
} |
|
|
|
|
|
|
|
.faceList { |
|
|
|
padding: 8px; |
|
|
|
display: flex; |
|
|
|
flex-wrap: wrap; |
|
|
|
justify-content: flex-start; |
|
|
|
width: 100%; |
|
|
|
height: 160px; |
|
|
|
height: 180px; |
|
|
|
overflow-y: scroll; |
|
|
|
.faceItem { |
|
|
|
position: relative; |
|
|
|
margin-right: 10px; |
|
|
|
margin-bottom: 10px; |
|
|
|
margin-right: 35px; |
|
|
|
margin-bottom: 35px; |
|
|
|
width: 150px; |
|
|
|
height: 150px; |
|
|
|
padding: 0 25px; |
|
|
|
// padding: 0 25px; |
|
|
|
line-height: 150px; |
|
|
|
text-align: center; |
|
|
|
border-radius: 50%; |
|
|
|
border: 2px solid #000; |
|
|
|
overflow: hidden; |
|
|
|
input { |
|
|
|
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; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
opacity: 0; |
|
|
|
right: 0; |
|
|
|
bottom: 0; |
|
|
|
z-index: 3; |
|
|
|
width: 150px; |
|
|
|
height: 150px; |
|
|
|
border-radius: 50%; |
|
|
|
background-color: #fbf8f8; |
|
|
|
overflow: hidden; |
|
|
|
img { |
|
|
|
position: absolute; |
|
|
|
top: 50%; |
|
|
|
left: 50%; |
|
|
|
transform: translate(-50%, -50%); |
|
|
|
width: 100%; |
|
|
|
} |
|
|
|
} |
|
|
|
.uploadImg { |
|
|
|
line-height: 145px; |
|
|
@@ -632,16 +912,28 @@ onMounted(() => { |
|
|
|
font-weight: 700; |
|
|
|
text-align: center; |
|
|
|
} |
|
|
|
p { |
|
|
|
height: 30px; |
|
|
|
} |
|
|
|
img { |
|
|
|
width: 100%; |
|
|
|
} |
|
|
|
.img { |
|
|
|
width: 100px; |
|
|
|
height: 100px; |
|
|
|
} |
|
|
|
.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%) |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@@ -664,7 +956,6 @@ onMounted(() => { |
|
|
|
.text { |
|
|
|
padding: 10px; |
|
|
|
border: 1px solid #000; |
|
|
|
|
|
|
|
.el-button { |
|
|
|
float: right; |
|
|
|
margin-top: 10px; |
|
|
@@ -685,9 +976,18 @@ onMounted(() => { |
|
|
|
height: 50px; |
|
|
|
margin-top: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
:deep(.el-input .is-focus) { |
|
|
|
// box-shadow: none !important; |
|
|
|
// box-shadow: 0 0 0 1px #000 !important; |
|
|
|
} |
|
|
|
} |
|
|
|
.card2 { |
|
|
|
padding: 10px; |
|
|
|
.el-icon { |
|
|
|
// color: red; |
|
|
|
vertical-align: text-top; |
|
|
|
} |
|
|
|
> div { |
|
|
|
position: relative; |
|
|
|
margin-top: 10px; |
|
|
@@ -704,6 +1004,7 @@ onMounted(() => { |
|
|
|
} |
|
|
|
.uploadAudio { |
|
|
|
padding: 20px; |
|
|
|
// margin-top: 30px; |
|
|
|
margin-bottom: 20px; |
|
|
|
height: 70px; |
|
|
|
.btnBox { |
|
|
@@ -733,18 +1034,35 @@ onMounted(() => { |
|
|
|
height: 170px; |
|
|
|
} |
|
|
|
.uploadVideo { |
|
|
|
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; |
|
|
|
} |
|
|
|
video { |
|
|
|
position: absolute; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
z-index: -1; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
} |
|
|
|
} |
|
|
|
> .el-button { |
|
|
|
width: 100%; |
|
|
|
height: 50px; |
|
|
|
margin-top: 10px; |
|
|
|
// background-color: #000; |
|
|
|
} |
|
|
|
} |
|
|
|
.card3 { |
|
|
|
.text { |
|
|
|