@@ -12,6 +12,18 @@ export function personPhotoList(pageNum, pageSize, sendType) { | |||
}) | |||
} | |||
/** | |||
* @description 获取人脸列表 | |||
* @params pageNum, pageSize | |||
* @returns data | |||
*/ | |||
export function personPhotoUserListList(pageNum, pageSize, sendType) { | |||
return request({ | |||
url: `api/personPhoto/userList?pageNum=${pageNum}&pageSize=${pageSize}&sendType=${sendType}`, | |||
method: 'get' | |||
}) | |||
} | |||
/** | |||
* @description 上传图片 | |||
* @params data | |||
@@ -37,6 +49,18 @@ export function saveImgApi(data) { | |||
}) | |||
} | |||
/** | |||
* @description 删除图片 | |||
* @params id | |||
* @returns data | |||
*/ | |||
export function delImgApi(id) { | |||
return request({ | |||
url: `api/personPhoto/del?id=${id}`, | |||
method: 'get', | |||
}) | |||
} | |||
/** | |||
* @description 上传视频 | |||
* @params data | |||
@@ -105,10 +129,17 @@ export function chooseTypeApi(id) { | |||
* @params id | |||
* @returns data | |||
*/ | |||
export function previewAudioApi(genTxt, voiceId, voiceStyle) { | |||
// export function previewAudioApi(genTxt, voiceId, voiceStyle) { | |||
// return request({ | |||
// url: `api/voiceMould/preview?genTxt=${genTxt}&voiceId=${voiceId}&voiceStyle=${voiceStyle}`, | |||
// method: 'GET', | |||
// }) | |||
// } | |||
export function previewAudioApi(gen_txt, voice_id, voice_style) { | |||
return request({ | |||
url: `api/voiceMould/preview?genTxt=${genTxt}&voiceId=${voiceId}&voiceStyle=${voiceStyle}`, | |||
method: 'GET', | |||
url: `api/voiceMould/preview`, | |||
method: 'POST', | |||
data: { gen_txt, voice_id, voice_style } | |||
}) | |||
} | |||
@@ -81,6 +81,7 @@ export default { | |||
draftText: "Draft", | |||
generatingText: "The video is generating, please wait a moment", | |||
generationFailedText: "The video generate is failed, Reason:", | |||
edit:'edit' | |||
}, | |||
// 个人账户 | |||
@@ -81,6 +81,7 @@ export default { | |||
draftText: "草稿", | |||
generatingText: "视频正在生成中,请稍等哦", | |||
generationFailedText: "视频生成失败。原因:", | |||
edit:'编辑' | |||
}, | |||
// 个人账户 | |||
@@ -23,7 +23,7 @@ const tagsViewStore = useTagsViewStore(); | |||
/* 50= navbar 50 */ | |||
min-height: calc(100vh - 80px); | |||
overflow: hidden; | |||
// overflow: hidden; | |||
// background-color: var(--el-bg-color-page); | |||
background-color: #000; | |||
} | |||
@@ -5,7 +5,6 @@ declare global { | |||
const ElForm: typeof import('element-plus/es')['ElForm'] | |||
const ElMessage: typeof import('element-plus/es')['ElMessage'] | |||
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox'] | |||
const ElTree: typeof import('element-plus/es')['ElTree'] | |||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] | |||
const autoResetRef: typeof import('@vueuse/core')['autoResetRef'] | |||
const computed: typeof import('vue')['computed'] | |||
@@ -275,7 +274,6 @@ declare module 'vue' { | |||
readonly ElForm: UnwrapRef<typeof import('element-plus/es')['ElForm']> | |||
readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']> | |||
readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']> | |||
readonly ElTree: UnwrapRef<typeof import('element-plus/es')['ElTree']> | |||
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']> | |||
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']> | |||
readonly computed: UnwrapRef<typeof import('vue')['computed']> | |||
@@ -49,11 +49,13 @@ declare module '@vue/runtime-core' { | |||
IEpCaretBottom: typeof import('~icons/ep/caret-bottom')['default'] | |||
IEpCaretTop: typeof import('~icons/ep/caret-top')['default'] | |||
IEpClose: typeof import('~icons/ep/close')['default'] | |||
IEpCloseBold: typeof import('~icons/ep/close-bold')['default'] | |||
IEpCollection: typeof import('~icons/ep/collection')['default'] | |||
IEpDelete: typeof import('~icons/ep/delete')['default'] | |||
IEpDownload: typeof import('~icons/ep/download')['default'] | |||
IEpEdit: typeof import('~icons/ep/edit')['default'] | |||
IEpGoods: typeof import('~icons/ep/goods')['default'] | |||
IEpLoading: typeof import('~icons/ep/loading')['default'] | |||
IEpMenu: typeof import('~icons/ep/menu')['default'] | |||
IEpMic: typeof import('~icons/ep/mic')['default'] | |||
IEpPlus: typeof import('~icons/ep/plus')['default'] | |||
@@ -7,7 +7,11 @@ | |||
<div class="left-top" v-show="!showUploadBtn"> | |||
<el-row class="justify-between"> | |||
<!-- title框 --> | |||
<div class="flex justify-between" style="width: 300px"> | |||
<div | |||
v-show="!submitImgBtn" | |||
class="flex justify-between" | |||
style="width: 300px" | |||
> | |||
<el-input | |||
v-model="title" | |||
:placeholder="$t('createVideo.typeTitle')" | |||
@@ -18,12 +22,7 @@ | |||
<div class="btnBox" v-show="submitImgBtn"> | |||
<button class="uploadBtn"> | |||
{{ $t("createVideo.reselect") }} | |||
<input | |||
accept="image/*" | |||
type="file" | |||
@click="e.target.value = null" | |||
@change="lookImg" | |||
/> | |||
<input accept="image/*" type="file" @change="lookImg" /> | |||
</button> | |||
<button class="uploadBtn" @click="changeFile"> | |||
{{ $t("createVideo.sureUpload") }} | |||
@@ -44,21 +43,34 @@ | |||
: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"> | |||
+ | |||
<input | |||
accept="image/*" | |||
type="file" | |||
@click="e.target.value = null" | |||
@change="lookImg" | |||
/> | |||
<input accept="image/*" type="file" @change="lookImg" /> | |||
</div> | |||
<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> | |||
<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> | |||
@@ -83,11 +95,7 @@ | |||
</div> | |||
<div class="faceList"> | |||
<!-- 上传图片组件 --> | |||
<div | |||
v-if="showFace == 1" | |||
class="faceItem" | |||
@click="showUploadBtn = true" | |||
> | |||
<div v-if="showFace == 1" class="faceItem" @click="clickAddBtn"> | |||
<span class="uploadImg">+ </span> | |||
</div> | |||
<my-loading :isLoading="feceItemLoading"></my-loading> | |||
@@ -114,13 +122,6 @@ | |||
<el-tab-pane :label="$t('createVideo.typeScript')"> | |||
<div class="card1"> | |||
<div class="text"> | |||
<el-input | |||
v-model="title" | |||
:placeholder="$t('createVideo.typeTitle')" | |||
/> | |||
<el-button type="primary"> | |||
{{ $t("createVideo.confirm") }} | |||
</el-button> | |||
<!-- 文本域 --> | |||
<el-input | |||
id="textInputId" | |||
@@ -142,7 +143,7 @@ | |||
<el-select | |||
@change="chooseType" | |||
v-model="language" | |||
placeholder="Select" | |||
:placeholder="$t('createVideo.select')" | |||
style="width: 100%" | |||
> | |||
<el-option | |||
@@ -169,7 +170,7 @@ | |||
@change="chooseStyle" | |||
:disabled="language ? false : true" | |||
v-model="sound" | |||
:placeholder="language ? 'Select' : 'Please select language'" | |||
:placeholder="$t('createVideo.select')" | |||
style="width: 100%" | |||
> | |||
<el-option | |||
@@ -184,7 +185,7 @@ | |||
<el-select | |||
:disabled="soundStyleOptions ? false : true" | |||
v-model="soundStyle" | |||
:placeholder="soundStyleOptions ? 'Select' : '暂无数据'" | |||
:placeholder="$t('createVideo.select')" | |||
style="width: 100%" | |||
> | |||
<el-option | |||
@@ -194,12 +195,25 @@ | |||
:value="item" | |||
/> | |||
</el-select> | |||
<!-- 生成视频 --> | |||
<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 | |||
> | |||
<!-- 保存视频 --> | |||
<el-button | |||
@click="saveOrUpdate(1, 'saveVideo')" | |||
color="#000" | |||
type="primary" | |||
style="margin-left: 0" | |||
> | |||
<my-loading :isLoading="createLoading"></my-loading> | |||
<span v-if="!createLoading">{{ | |||
$t("createVideo.saveVideo") | |||
}}</span></el-button | |||
> | |||
</div> | |||
</el-tab-pane> | |||
<!-- ------------------------ 2 --> | |||
@@ -208,7 +222,7 @@ | |||
<!-- 上传视频 --> | |||
<p> | |||
<el-icon class="icon-VideoCamera"><i-ep-VideoCamera /></el-icon> | |||
上传音频 | |||
{{ $t("createVideo.uploadAudio") }} | |||
</p> | |||
<div class="uploadVideo"> | |||
+ | |||
@@ -230,7 +244,7 @@ | |||
<!-- 录制MP3上传语音 --> | |||
<p> | |||
<el-icon class="icon-Mic"><i-ep-Mic /></el-icon> | |||
录制音频 | |||
{{ $t("createVideo.recordedAudio") }} | |||
</p> | |||
<div | |||
class="uploadAudio" | |||
@@ -242,14 +256,14 @@ | |||
:disabled="!isRecording" | |||
@click="startRecording" | |||
> | |||
开始录音 | |||
{{ $t("createVideo.startRecorded") }} | |||
</button> | |||
<button | |||
class="pointer" | |||
@click="stopRecording" | |||
:disabled="isRecording" | |||
> | |||
停止录音 | |||
{{ $t("createVideo.stopRecorded") }} | |||
</button> | |||
</div> | |||
<!-- <button @click="playRecording">播放录音</button> --> | |||
@@ -258,12 +272,25 @@ | |||
上传音频 | |||
</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> | |||
<!-- 保存视频 --> | |||
<el-button | |||
@click="saveOrUpdate(2, 'saveVideo')" | |||
color="#000" | |||
type="primary" | |||
style="margin-left: 0" | |||
> | |||
<my-loading :isLoading="createLoading"></my-loading> | |||
<span v-if="!createLoading">{{ | |||
$t("createVideo.saveVideo") | |||
}}</span></el-button | |||
> | |||
</div> | |||
</el-tab-pane> | |||
<!-- ----------------------- 3 --> | |||
@@ -355,9 +382,13 @@ import { | |||
createVideoApi, | |||
previewAudioApi, | |||
} from "@/apis/createVideo"; | |||
import { useI18n } from "vue-i18n"; | |||
import Recorder from "js-audio-recorder"; //mp3插件 | |||
import imageCompression from "browser-image-compression"; //压缩图片插件 | |||
const { locale } = useI18n(); | |||
const lanChange = ref(locale); | |||
//#region 头像区的逻辑 | |||
// 获取AI头像 | |||
const AiFaceList = ref([]); | |||
@@ -399,18 +430,27 @@ function setImgUrl(url, id) { | |||
//#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; | |||
if (e.target.files[0]) { | |||
faceItemActive.value = null; | |||
imgUrl.value = null; | |||
imgData.value = null; | |||
showUploadBtn.value = true; | |||
submitImgBtn.value = false; | |||
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; | |||
} else { | |||
return; | |||
} | |||
} | |||
//#endregion ------------------ | |||
@@ -422,6 +462,11 @@ const imgUrl = ref(""); //图片回显路径 | |||
const imgData = ref(""); // 上传图片文件 | |||
const showUploadBtn = ref(false); //上传图片+号的显示隐藏 | |||
const submitImgBtn = ref(false); //右上角俩按钮显示与隐藏 | |||
// 点击AI头像区的+号 | |||
function clickAddBtn() { | |||
faceItemActive.value = null; | |||
showUploadBtn.value = true; | |||
} | |||
// 上传图片 | |||
async function changeFile() { | |||
imgUrl.value = URL.createObjectURL(imgData.value); | |||
@@ -429,13 +474,21 @@ async function changeFile() { | |||
const timestamp = Date.now(); | |||
formData.append("file", imgData.value, timestamp + ".png"); | |||
try { | |||
// 上传图片 | |||
const res = await awsImgUpload(formData); | |||
if (res.code == 200) { | |||
ElMessage.success("上传成功!"); | |||
// 保存图片 | |||
const res2 = await saveImgApi({ material: res.data.url }); | |||
// 重新获取列表 | |||
getAiFaceList(1, 100, 1); | |||
if (res2.code == 200) { | |||
ElMessage.success( | |||
lanChange.value == "zh-cn" ? `上传成功` : `Upload successfully` | |||
); | |||
} else { | |||
ElMessage.error("上传失败!"); | |||
ElMessage.error( | |||
lanChange.value == "zh-cn" ? `上传失败` : `Upload failure` | |||
); | |||
} | |||
const res2 = await saveImgApi({ material: res.data.url }); | |||
} catch (error) { | |||
ElMessage.error(error); | |||
} | |||
@@ -503,11 +556,19 @@ async function chooseStyle() { | |||
const previewAudioUrl = ref(null); | |||
async function getPreviewAudio() { | |||
if (!textareaContent.value) { | |||
ElMessage.error("您还没有输入文案"); | |||
ElMessage.error( | |||
lanChange.value == "zh-cn" | |||
? `您还没有输入文案` | |||
: `You have not entered the copy yet` | |||
); | |||
return; | |||
} | |||
if (!sound.value) { | |||
ElMessage.error("您还没有选择声音"); | |||
ElMessage.error( | |||
lanChange.value == "zh-cn" | |||
? `您还没有选择声音` | |||
: `You have not selected the sound` | |||
); | |||
return; | |||
} | |||
@@ -565,7 +626,7 @@ const playRecording = () => { | |||
} | |||
}; | |||
// 上传音频 | |||
async function uploadAudio() { | |||
async function uploadAudio(isSaveVideo) { | |||
createLoading.value = true; | |||
let formData = new FormData(); | |||
const timestamp = Date.now(); | |||
@@ -576,12 +637,14 @@ async function uploadAudio() { | |||
if (res) { | |||
// ElMessage.success("上传成功!"); | |||
} else { | |||
ElMessage.error("音频上传失败!"); | |||
ElMessage.error( | |||
lanChange.value == "zh-cn" ? `上传音频失败!` : `Failed to upload audio!` | |||
); | |||
return; | |||
} | |||
// 查询进度 | |||
intervalId = setInterval(() => { | |||
uploadProgress(res.data.videoId); | |||
uploadProgress(res.data.videoId, isSaveVideo); | |||
}, 1000); | |||
// ElMessage.success("上传成功!"); | |||
} catch (error) { | |||
@@ -604,7 +667,7 @@ const handleFileChange = async () => { | |||
}; | |||
// 获取视频上传进度 | |||
const afterSaveAudioId = ref(null); | |||
async function uploadProgress(videoId) { | |||
async function uploadProgress(videoId, isSaveVideo) { | |||
const res = await uploadProgressApi(videoId); | |||
if (res.data == "complete") { | |||
clearInterval(intervalId); | |||
@@ -625,9 +688,20 @@ async function uploadProgress(videoId) { | |||
}; | |||
try { | |||
const res3 = await saveOrUpdateApi(saveOrUpdateData); // 保存数据 | |||
if (isSaveVideo == "saveVideo") { | |||
ElMessage.success( | |||
lanChange.value == "zh-cn" ? `已保存为草稿` : `Saved as draft` | |||
); | |||
createLoading.value = false; | |||
return; | |||
} | |||
const res4 = await createVideoApi({ id: res3.data.id }); // 生成视频 | |||
if (res4.message == "success") { | |||
ElMessage.success("视频正在生成,请耐心等待"); | |||
ElMessage.success( | |||
lanChange.value == "zh-cn" | |||
? `视频正在生成中,请耐心等待` | |||
: `The video is being generated, please wait patiently` | |||
); | |||
} | |||
createLoading.value = false; | |||
} catch (error) { | |||
@@ -644,7 +718,7 @@ const tabFrom = ref(1); | |||
const createLoading = ref(false); | |||
// 上传音频后,得到videoId | |||
// 保存数据 | |||
async function saveOrUpdate(index) { | |||
async function saveOrUpdate(index, isSaveVideo) { | |||
if (createLoading.value == true) { | |||
return; | |||
} | |||
@@ -661,9 +735,20 @@ async function saveOrUpdate(index) { | |||
createLoading.value = true; | |||
try { | |||
const res2 = await saveOrUpdateApi(saveOrUpdateData); // 保存数据 | |||
if (isSaveVideo == "saveVideo") { | |||
ElMessage.success( | |||
lanChange.value == "zh-cn" ? `已保存为草稿` : `Saved as draft` | |||
); | |||
createLoading.value = false; | |||
return; | |||
} | |||
const res3 = await createVideoApi({ id: res2.data.id }); // 生成视频 | |||
if (res3.message == "success") { | |||
ElMessage.success("视频正在生成,请耐心等待"); | |||
ElMessage.success( | |||
lanChange.value == "zh-cn" | |||
? `视频正在生成中,请耐心等待` | |||
: `The video is being generated, please wait patiently` | |||
); | |||
} | |||
createLoading.value = false; | |||
} catch (error) { | |||
@@ -673,7 +758,7 @@ async function saveOrUpdate(index) { | |||
} | |||
if (index == 2) { | |||
try { | |||
const res1 = await uploadAudio(); // 上传音频 | |||
const res1 = await uploadAudio(isSaveVideo); // 上传音频 | |||
} catch (error) { | |||
ElMessage.error(error); | |||
createLoading.value = false; | |||
@@ -768,13 +853,34 @@ onMounted(() => { | |||
width: 100%; | |||
height: 100%; | |||
border: 1px solid #000; | |||
.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: 60px; | |||
width: 100px; | |||
height: 100px; | |||
background-color: green; | |||
border-radius: 50%; | |||
.icon { | |||
position: absolute; | |||
top: 0%; | |||
right: -5%; | |||
border: 2px solid #00ff95; | |||
color: #00ff95; | |||
} | |||
} | |||
.el-upload { | |||
position: absolute; | |||
@@ -791,7 +897,7 @@ onMounted(() => { | |||
font-size: 50px; | |||
line-height: 100px; | |||
text-align: center; | |||
background-color: pink; | |||
background-color: #ccc; | |||
border-radius: 50%; | |||
} | |||
@@ -800,7 +906,7 @@ onMounted(() => { | |||
// background-color: #795562; | |||
display: flex; | |||
justify-content: space-evenly; | |||
width: 500px; | |||
width: 700px; | |||
height: 100px; | |||
> div { | |||
@@ -809,6 +915,13 @@ onMounted(() => { | |||
height: 100px; | |||
background-color: #ccc; | |||
border-radius: 50%; | |||
.icon { | |||
position: absolute; | |||
top: 0%; | |||
right: -5%; | |||
border: 2px solid red; | |||
color: red; | |||
} | |||
} | |||
} | |||
} | |||
@@ -821,6 +934,7 @@ onMounted(() => { | |||
width: 100%; | |||
height: 100%; | |||
opacity: 0; | |||
cursor: pointer; | |||
} | |||
.icon { | |||
@@ -3,8 +3,8 @@ | |||
<!-- 左侧栏 --> | |||
<div class="left"> | |||
<!-- 顶部 --> | |||
<!-- 有图片时 --> | |||
<div class="left-top" v-show="!showUploadBtn"> | |||
<!-- 选中AiFace --> | |||
<div class="left-top" v-show="showUploadBtn == 1"> | |||
<el-row class="justify-between"> | |||
<!-- title框 --> | |||
<div | |||
@@ -18,24 +18,14 @@ | |||
/> | |||
<el-icon class="icon-edit"><i-ep-edit /></el-icon> | |||
</div> | |||
<!-- 上传按钮 --> | |||
<div class="btnBox" v-show="submitImgBtn"> | |||
<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> | |||
<!-- 没有图片时 --> | |||
<div class="left-top" v-show="showUploadBtn"> | |||
<!-- 选中需要上传的图片前 --> | |||
<div class="left-top" v-show="showUploadBtn == 2"> | |||
<!-- 中间展示大图 --> | |||
<div class="noImg"> | |||
<my-loading | |||
@@ -43,6 +33,9 @@ | |||
: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"> | |||
@@ -50,10 +43,84 @@ | |||
<input accept="image/*" type="file" @change="lookImg" /> | |||
</div> | |||
<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> | |||
<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" | |||
></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"> | |||
+ | |||
<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> | |||
<!-- 选中需要上传的图片前后 --> | |||
<div class="left-top" v-show="showUploadBtn == 4"> | |||
<el-row class="justify-between"> | |||
<!-- 上传按钮 --> | |||
<div class="btnBox" v-show="submitImgBtn"> | |||
<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> | |||
@@ -75,7 +142,8 @@ | |||
{{ $t("createVideo.personalWarehouse") }} | |||
</div> | |||
</div> | |||
<div class="faceList"> | |||
<!-- 系统相册 --> | |||
<div class="faceList" v-if="showFace == 0"> | |||
<!-- 上传图片组件 --> | |||
<div v-if="showFace == 1" class="faceItem" @click="clickAddBtn"> | |||
<span class="uploadImg">+ </span> | |||
@@ -95,6 +163,33 @@ | |||
s | |||
</div> | |||
</div> | |||
<!-- 个人相册 --> | |||
<div class="faceList" v-if="showFace == 1"> | |||
<!-- 上传图片组件 --> | |||
<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> | |||
</div> | |||
</div> | |||
<!-- 右侧栏 --> | |||
@@ -353,7 +448,9 @@ | |||
import { getCurrentInstance } from "vue"; | |||
import { | |||
personPhotoList, | |||
personPhotoUserListList, | |||
awsImgUpload, | |||
delImgApi, | |||
videoUpload, | |||
saveImgApi, | |||
uploadProgressApi, | |||
@@ -374,7 +471,9 @@ const lanChange = ref(locale); | |||
//#region 头像区的逻辑 | |||
// 获取AI头像 | |||
const AiFaceList = ref([]); | |||
const userAiFaceList = ref([]); | |||
const feceItemLoading = ref(false); | |||
const feceItemLoading2 = ref(false); | |||
function getAiFaceList(pageNum, pageSize, sendType) { | |||
feceItemLoading.value = true; | |||
personPhotoList(pageNum, pageSize, sendType) | |||
@@ -387,6 +486,18 @@ function getAiFaceList(pageNum, pageSize, sendType) { | |||
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"); | |||
}); | |||
} | |||
// 选择显示的face列表 | |||
const showFace = ref("0"); | |||
function ChangeShowFaceList(index) { | |||
@@ -395,7 +506,7 @@ function ChangeShowFaceList(index) { | |||
getAiFaceList(1, 100, 1); | |||
} | |||
if (index == 1) { | |||
getAiFaceList(1, 100, 3); | |||
getAiFaceUserList(1, 100, 3); | |||
} | |||
showFace.value = index; | |||
} | |||
@@ -403,10 +514,32 @@ const faceItemActive = ref(); //高亮处理和当前选择图片的ID | |||
// 点击aifece | |||
function setImgUrl(url, id) { | |||
faceItemActive.value = id; | |||
showUploadBtn.value = false; | |||
showUploadBtn.value = 1; | |||
submitImgBtn.value = false; | |||
imgUrl.value = url; | |||
} | |||
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; | |||
getAiFaceUserList(1, 100, 3); | |||
} catch (error) { | |||
ElMessage.error(errpr); | |||
} | |||
}); | |||
} | |||
//#endregion ------------------------------ | |||
//#region 预览图片 | |||
@@ -416,7 +549,7 @@ async function lookImg(e) { | |||
faceItemActive.value = null; | |||
imgUrl.value = null; | |||
imgData.value = null; | |||
showUploadBtn.value = true; | |||
showUploadBtn.value = 3; | |||
submitImgBtn.value = false; | |||
compressionImgLoad.value = true; | |||
// 压缩配置 | |||
@@ -427,7 +560,7 @@ async function lookImg(e) { | |||
const compressedFile = await imageCompression(e.target.files[0], options); | |||
imgUrl.value = URL.createObjectURL(compressedFile); | |||
imgData.value = compressedFile; | |||
showUploadBtn.value = false; | |||
showUploadBtn.value = 4; | |||
submitImgBtn.value = true; | |||
compressionImgLoad.value = false; | |||
} else { | |||
@@ -442,15 +575,17 @@ const title = ref(""); | |||
//#region 上传图片 | |||
const imgUrl = ref(""); //图片回显路径 | |||
const imgData = ref(""); // 上传图片文件 | |||
const showUploadBtn = ref(false); //上传图片+号的显示隐藏 | |||
const showUploadBtn = ref(1); //上传图片+号的显示隐藏 | |||
const submitImgBtn = ref(false); //右上角俩按钮显示与隐藏 | |||
// 点击AI头像区的+号 | |||
function clickAddBtn() { | |||
faceItemActive.value = null; | |||
showUploadBtn.value = true; | |||
showUploadBtn.value = 2; | |||
} | |||
// 上传图片 | |||
async function changeFile() { | |||
compressionImgLoad.value = true; | |||
showUploadBtn.value = 3; | |||
imgUrl.value = URL.createObjectURL(imgData.value); | |||
let formData = new FormData(); | |||
const timestamp = Date.now(); | |||
@@ -461,7 +596,9 @@ async function changeFile() { | |||
// 保存图片 | |||
const res2 = await saveImgApi({ material: res.data.url }); | |||
// 重新获取列表 | |||
getAiFaceList(1, 100, 1); | |||
compressionImgLoad.value = false; | |||
showUploadBtn.value = 4; | |||
getAiFaceUserList(1, 100, 3); | |||
if (res2.code == 200) { | |||
ElMessage.success( | |||
lanChange.value == "zh-cn" ? `上传成功` : `Upload successfully` | |||
@@ -661,6 +798,7 @@ async function uploadProgress(videoId, isSaveVideo) { | |||
} | |||
// 定义参数 | |||
const saveOrUpdateData = { | |||
title: title.value, | |||
personPhotoId: faceItemActive.value, //任务照片id, | |||
voiceFrom: tabFrom.value, //:声音来源 1:来自选择模板,2:来自用户上传 | |||
paperwork: textareaContent.value, //文案 | |||
@@ -706,6 +844,7 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
} | |||
tabFrom.value = index; | |||
const saveOrUpdateData = { | |||
title: title.value, | |||
personPhotoId: faceItemActive.value, //任务照片id, | |||
voiceFrom: tabFrom.value, //:声音来源 1:来自选择模板,2:来自用户上传 | |||
paperwork: textareaContent.value, //文案 | |||
@@ -765,6 +904,7 @@ const t = globalProperties.$t(string); | |||
onMounted(() => { | |||
getAiFaceList(1, 100, 1); | |||
getAiFaceUserList(1, 100, 3); | |||
voiceTotal(); | |||
chooseType(); | |||
}); | |||
@@ -835,13 +975,34 @@ onMounted(() => { | |||
width: 100%; | |||
height: 100%; | |||
border: 1px solid #000; | |||
.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: 60px; | |||
width: 100px; | |||
height: 100px; | |||
background-color: green; | |||
border-radius: 50%; | |||
.icon { | |||
position: absolute; | |||
top: 0%; | |||
right: -5%; | |||
border: 2px solid #00ff95; | |||
color: #00ff95; | |||
} | |||
} | |||
.el-upload { | |||
position: absolute; | |||
@@ -858,7 +1019,7 @@ onMounted(() => { | |||
font-size: 50px; | |||
line-height: 100px; | |||
text-align: center; | |||
background-color: pink; | |||
background-color: #ccc; | |||
border-radius: 50%; | |||
} | |||
@@ -867,7 +1028,7 @@ onMounted(() => { | |||
// background-color: #795562; | |||
display: flex; | |||
justify-content: space-evenly; | |||
width: 500px; | |||
width: 700px; | |||
height: 100px; | |||
> div { | |||
@@ -876,6 +1037,13 @@ onMounted(() => { | |||
height: 100px; | |||
background-color: #ccc; | |||
border-radius: 50%; | |||
.icon { | |||
position: absolute; | |||
top: 0%; | |||
right: -5%; | |||
border: 2px solid red; | |||
color: red; | |||
} | |||
} | |||
} | |||
} | |||
@@ -888,6 +1056,7 @@ onMounted(() => { | |||
width: 100%; | |||
height: 100%; | |||
opacity: 0; | |||
cursor: pointer; | |||
} | |||
.icon { | |||
@@ -973,6 +1142,20 @@ onMounted(() => { | |||
width: 100%; | |||
} | |||
} | |||
.deleteIcon { | |||
position: absolute; | |||
top: 0; | |||
right: 15px; | |||
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: 145px; | |||
font-size: 50px; | |||
@@ -68,12 +68,17 @@ | |||
/></el-icon> | |||
<div class="showBtn" @click.stop="mouseenter(item)">...</div> | |||
<div class="btns" v-show="showPopup"> | |||
<div class="btns-item" @click.stop="handleDownload(item.id)"> | |||
<!-- 下载按钮 --> | |||
<div | |||
class="btns-item" | |||
@click.stop="handleDownload(item.videoPlayUrl)" | |||
> | |||
<div class="btns-item-icon"> | |||
<el-icon class="icon-delete"><i-ep-download /></el-icon> | |||
</div> | |||
<div class="text">{{ $t("myCreating.download") }}</div> | |||
</div> | |||
<!-- 删除按钮 --> | |||
<div | |||
class="btns-item" | |||
@click.stop="handelDelete(item.id, item.title)" | |||
@@ -134,16 +139,19 @@ | |||
}}</span> | |||
</div> | |||
</div> | |||
<!-- 有视频路径的页脚 --> | |||
<template #footer v-if="presentItem.videoPlayUrl"> | |||
<span class="dialog-footer"> | |||
<!-- dialog下载按钮 --> | |||
<button | |||
class="elBtn" | |||
type="primary" | |||
@click.stop="handleDownload(presentItem.id)" | |||
@click.stop="handleDownload(presentItem.videoPlayUrl)" | |||
> | |||
<el-icon class="icon-delete"><i-ep-download /></el-icon | |||
>{{ $t("myCreating.download") }} | |||
</button> | |||
<!-- dialog删除按钮 --> | |||
<button | |||
class="elBtn" | |||
@click.stop="handelDelete(presentItem.id, presentItem.title)" | |||
@@ -153,6 +161,15 @@ | |||
</button> | |||
</span> | |||
</template> | |||
<!-- 无视频路径的页脚 --> | |||
<template #footer v-if="!presentItem.videoPlayUrl"> | |||
<span class="dialog-footer"> | |||
<!-- dialog编辑按钮 --> | |||
<button class="elBtn" type="primary" @click.stop=""> | |||
{{ $t("myCreating.edit") }} | |||
</button> | |||
</span> | |||
</template> | |||
</el-dialog> | |||
<div v-if="!isLoading" class="pagination"> | |||
@@ -171,6 +188,7 @@ | |||
</div> | |||
</div> | |||
</template> | |||
<script setup> | |||
import { userPhotoVideoList, delUserPhotoVideoByID } from "@/apis/myCreating"; | |||
import { timestampToTime } from "@/utils/tools"; | |||
@@ -221,8 +239,20 @@ function mouseenter(item) { | |||
presentItem.value = item; | |||
showPopup.value = !showPopup.value; | |||
} | |||
function handleDownload() {} | |||
// 下载 | |||
function handleDownload(itemVideoPlayUrl) { | |||
if (itemVideoPlayUrl) { | |||
const link = document.createElement("a"); | |||
link.href = itemVideoPlayUrl; | |||
document.body.appendChild(link); | |||
link.click(); | |||
document.body.removeChild(link); | |||
} else { | |||
ElMessage.error( | |||
lanChange.value == "zh-cn" ? `无法下载` : `Unable to download` | |||
); | |||
} | |||
} | |||
function goCreate() { | |||
router.push("/createVideo"); | |||
@@ -300,6 +330,7 @@ function delPhotoVideo(videoID) { | |||
console.log(res, "res"); | |||
const msg = lanChange.value == "zh-cn" ? `删除成功!` : `Success !`; | |||
ElMessage.success(msg); | |||
showDialog.value = false; | |||
getPhotoVideoList(pageNum.value, pageSize.value, title.value); | |||
}) | |||
.catch((err) => { | |||
@@ -316,8 +347,8 @@ onMounted(() => { | |||
<style lang="scss" scoped> | |||
.page { | |||
height: 1200px; | |||
padding: 50px 130px; | |||
min-height: calc(100vh - 80px); | |||
padding: 20px 130px; | |||
background-color: #fff; | |||
border-radius: 25px 0 0; | |||
.top { | |||
@@ -338,8 +369,9 @@ onMounted(() => { | |||
flex-wrap: wrap; | |||
justify-content: flex-start; | |||
width: 100%; | |||
height: 200px; | |||
// height: 200px; | |||
margin-top: 20px; | |||
padding-bottom: 50px; | |||
cursor: pointer; | |||
.workItem { | |||
position: relative; | |||
@@ -356,6 +388,7 @@ onMounted(() => { | |||
height: 170px; | |||
cursor: pointer; | |||
padding: 10px; | |||
overflow: hidden; | |||
.coverImg { | |||
max-width: 90%; | |||
max-height: 170px; | |||
@@ -541,7 +574,7 @@ onMounted(() => { | |||
} | |||
.pagination { | |||
position: fixed; | |||
bottom: 50px; | |||
bottom: 20px; | |||
left: 50%; | |||
transform: translateX(-50%); | |||
background-color: #ffffff; | |||
@@ -583,7 +616,8 @@ onMounted(() => { | |||
padding: 10px 40px 30px 40px; | |||
video { | |||
width: 100%; | |||
max-width: 100%; | |||
max-height: 600px; | |||
margin: auto; | |||
} | |||
.insteadVideo { | |||