|
|
@@ -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") }} |
|
|
@@ -39,17 +44,12 @@ |
|
|
|
</div> |
|
|
|
<div 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><div class="icon">×</div></div> |
|
|
@@ -89,8 +89,9 @@ |
|
|
|
<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" |
|
|
|
> |
|
|
@@ -115,15 +116,15 @@ |
|
|
|
<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> |
|
|
|
<div @click="insertIcon">🕗</div> |
|
|
|
</div> |
|
|
|
<p>{{ $t("createVideo.languages") }}</p> |
|
|
|
<el-select |
|
|
@@ -145,7 +146,7 @@ |
|
|
|
style="width: 100%" |
|
|
|
> |
|
|
|
<el-option |
|
|
|
v-for="item in languageOptions" |
|
|
|
v-for="item in soundOptions" |
|
|
|
:key="item.value" |
|
|
|
:label="item.label" |
|
|
|
:value="item.value" |
|
|
@@ -158,13 +159,13 @@ |
|
|
|
style="width: 100%" |
|
|
|
> |
|
|
|
<el-option |
|
|
|
v-for="item in languageOptions" |
|
|
|
v-for="item in soundStyleOptions" |
|
|
|
:key="item.value" |
|
|
|
:label="item.label" |
|
|
|
:value="item.value" |
|
|
|
/> |
|
|
|
</el-select> |
|
|
|
<el-button type="primary">{{ |
|
|
|
<el-button color="#000" type="primary">{{ |
|
|
|
$t("createVideo.generateVideo") |
|
|
|
}}</el-button> |
|
|
|
</div> |
|
|
@@ -172,7 +173,26 @@ |
|
|
|
<!-- ------------------------ 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 type="file" ref="fileInput" @change="handleFileChange" /> |
|
|
|
<video |
|
|
|
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' : ''" |
|
|
@@ -199,20 +219,9 @@ |
|
|
|
上传音频 |
|
|
|
</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> |
|
|
|
</div> |
|
|
|
<el-button color="#000" type="primary">{{ |
|
|
|
$t("createVideo.generateVideo") |
|
|
|
}}</el-button> |
|
|
|
</div> |
|
|
|
</el-tab-pane> |
|
|
|
<!-- ----------------------- 3 --> |
|
|
@@ -287,13 +296,14 @@ |
|
|
|
|
|
|
|
<script setup> |
|
|
|
import { getCurrentInstance } from "vue"; |
|
|
|
import Recorder from "js-audio-recorder"; |
|
|
|
import { |
|
|
|
personPhotoList, |
|
|
|
awsImgUpload, |
|
|
|
videoUpload, |
|
|
|
saveImgApi, |
|
|
|
} from "@/apis/createVideo"; |
|
|
|
import Recorder from "js-audio-recorder"; //mp3插件 |
|
|
|
import imageCompression from "browser-image-compression"; //压缩图片插件 |
|
|
|
|
|
|
|
// 获取AI头像 |
|
|
|
const AiFaceList = ref([]); |
|
|
@@ -319,14 +329,27 @@ function ChangeShowFaceList(index) { |
|
|
|
const title = ref(""); |
|
|
|
|
|
|
|
// 上传图片 |
|
|
|
const imgUrl = ref(""); |
|
|
|
const imgData = ref(""); |
|
|
|
const showUploadBtn = ref(false); |
|
|
|
const imgUrl = ref(""); //图片回显路径 |
|
|
|
const imgData = ref(""); // 上传图片文件 |
|
|
|
const showUploadBtn = ref(false); //上传图片+号的显示隐藏 |
|
|
|
const submitImgBtn = ref(false); //右上角俩按钮显示与隐藏 |
|
|
|
|
|
|
|
// 预览图片 |
|
|
|
function lookImg(e) { |
|
|
|
imgUrl.value = URL.createObjectURL(e.target.files[0]); |
|
|
|
imgData.value = e.target.files[0]; |
|
|
|
async function lookImg(e) { |
|
|
|
// imgUrl.value = URL.createObjectURL(e.target.files[0]); |
|
|
|
// imgData.value = e.target.files[0]; |
|
|
|
// showUploadBtn.value = false; |
|
|
|
// submitImgBtn.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; |
|
|
|
} |
|
|
|
// 上传图片 |
|
|
|
async function changeFile() { |
|
|
@@ -346,14 +369,75 @@ async function changeFile() { |
|
|
|
ElMessage.error(error); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const faceItemActive = ref(); |
|
|
|
// 点击aifece |
|
|
|
function setImgUrl(url) { |
|
|
|
function setImgUrl(url, id) { |
|
|
|
faceItemActive.value = id; |
|
|
|
showUploadBtn.value = false; |
|
|
|
submitImgBtn.value = false; |
|
|
|
imgUrl.value = url; |
|
|
|
} |
|
|
|
|
|
|
|
// 录制MP3上传语音 |
|
|
|
//#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 = reactive([ |
|
|
|
{ |
|
|
|
value: "0", |
|
|
|
label: "中文", |
|
|
|
}, |
|
|
|
{ |
|
|
|
value: "1", |
|
|
|
label: "English", |
|
|
|
}, |
|
|
|
]); |
|
|
|
const soundOptions = reactive([ |
|
|
|
{ |
|
|
|
value: "0", |
|
|
|
label: "老人", |
|
|
|
}, |
|
|
|
{ |
|
|
|
value: "1", |
|
|
|
label: "小孩", |
|
|
|
}, |
|
|
|
]); |
|
|
|
const soundStyleOptions = reactive([ |
|
|
|
{ |
|
|
|
value: "0", |
|
|
|
label: "生气", |
|
|
|
}, |
|
|
|
{ |
|
|
|
value: "1", |
|
|
|
label: "抑郁", |
|
|
|
}, |
|
|
|
]); |
|
|
|
//#endregion |
|
|
|
|
|
|
|
//#region 录制MP3上传语音 |
|
|
|
const parameter = { |
|
|
|
sampleBits: 16, // 采样位数,支持 8 或 16,默认是16 |
|
|
|
sampleRate: 8000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000 |
|
|
@@ -402,8 +486,9 @@ async function uploadAudio(params) { |
|
|
|
ElMessage.error(error); |
|
|
|
} |
|
|
|
} |
|
|
|
//#endregion ------------------------------------ |
|
|
|
|
|
|
|
// 上传视频功能 |
|
|
|
//#region 上传视频功能 |
|
|
|
const fileInput = ref(null); |
|
|
|
const videoSrc = ref(null); |
|
|
|
const handleFileChange = () => { |
|
|
@@ -413,20 +498,11 @@ const handleFileChange = () => { |
|
|
|
videoSrc.value = videoUrl; |
|
|
|
} |
|
|
|
}; |
|
|
|
//#endregion -------------------------------------- |
|
|
|
|
|
|
|
// card3的 |
|
|
|
let language = ref(""); |
|
|
|
//#region card3的 |
|
|
|
|
|
|
|
let languageOptions = reactive([ |
|
|
|
{ |
|
|
|
value: "Option1", |
|
|
|
label: "Option1", |
|
|
|
}, |
|
|
|
{ |
|
|
|
value: "Option2", |
|
|
|
label: "Option2", |
|
|
|
}, |
|
|
|
]); |
|
|
|
//#endregion --------------------------- |
|
|
|
|
|
|
|
// $t在script中的使用 |
|
|
|
const { |
|
|
@@ -603,6 +679,7 @@ onMounted(() => { |
|
|
|
} |
|
|
|
|
|
|
|
.faceList { |
|
|
|
padding: 3px; |
|
|
|
display: flex; |
|
|
|
flex-wrap: wrap; |
|
|
|
justify-content: flex-start; |
|
|
@@ -611,7 +688,7 @@ onMounted(() => { |
|
|
|
overflow-y: scroll; |
|
|
|
.faceItem { |
|
|
|
position: relative; |
|
|
|
margin-right: 10px; |
|
|
|
margin-right: 13px; |
|
|
|
margin-bottom: 10px; |
|
|
|
width: 150px; |
|
|
|
height: 150px; |
|
|
@@ -619,7 +696,9 @@ onMounted(() => { |
|
|
|
line-height: 150px; |
|
|
|
text-align: center; |
|
|
|
border-radius: 50%; |
|
|
|
border: 2px solid #000; |
|
|
|
background-color: #fbf8f8; |
|
|
|
border: 2px solid #fff; |
|
|
|
box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 3px 3px; |
|
|
|
overflow: hidden; |
|
|
|
input { |
|
|
|
position: absolute; |
|
|
@@ -647,6 +726,15 @@ onMounted(() => { |
|
|
|
border-radius: 50%; |
|
|
|
} |
|
|
|
} |
|
|
|
.faceItemActive { |
|
|
|
background: linear-gradient( |
|
|
|
270deg, |
|
|
|
rgb(201, 113, 255) 24.97%, |
|
|
|
rgb(92, 121, 252) 100% |
|
|
|
); |
|
|
|
// border: 2px solid #fff; |
|
|
|
// box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 3px 3px; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@@ -667,7 +755,6 @@ onMounted(() => { |
|
|
|
.text { |
|
|
|
padding: 10px; |
|
|
|
border: 1px solid #000; |
|
|
|
|
|
|
|
.el-button { |
|
|
|
float: right; |
|
|
|
margin-top: 10px; |
|
|
@@ -688,9 +775,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; |
|
|
@@ -707,6 +803,7 @@ onMounted(() => { |
|
|
|
} |
|
|
|
.uploadAudio { |
|
|
|
padding: 20px; |
|
|
|
// margin-top: 30px; |
|
|
|
margin-bottom: 20px; |
|
|
|
height: 70px; |
|
|
|
.btnBox { |
|
|
@@ -736,7 +833,13 @@ onMounted(() => { |
|
|
|
height: 170px; |
|
|
|
} |
|
|
|
.uploadVideo { |
|
|
|
text-align: center; |
|
|
|
|
|
|
|
margin-bottom: 20px; |
|
|
|
height: 100px; |
|
|
|
font-size: 50px; |
|
|
|
font-weight: 700; |
|
|
|
line-height: 100px; |
|
|
|
input { |
|
|
|
position: absolute; |
|
|
|
width: 100%; |
|
|
@@ -748,6 +851,12 @@ onMounted(() => { |
|
|
|
height: 100%; |
|
|
|
} |
|
|
|
} |
|
|
|
> .el-button { |
|
|
|
width: 100%; |
|
|
|
height: 50px; |
|
|
|
margin-top: 10px; |
|
|
|
// background-color: #000; |
|
|
|
} |
|
|
|
} |
|
|
|
.card3 { |
|
|
|
.text { |
|
|
|