congzc vor 2 Jahren
Ursprung
Commit
94e2acbb95
5 geänderte Dateien mit 443 neuen und 86 gelöschten Zeilen
  1. +52
    -0
      src/components/myLoading.vue
  2. +5
    -0
      src/main.ts
  3. +1
    -0
      src/types/components.d.ts
  4. +365
    -76
      src/views/createVideo/index copy.vue
  5. +20
    -10
      src/views/createVideo/index.vue

+ 52
- 0
src/components/myLoading.vue Datei anzeigen

@@ -0,0 +1,52 @@
<template>
<div v-if="isLoading" class="loadingIcon">
<div>
<el-icon class="is-loading">
<svg
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
data-v-ea893728=""
>
<path
fill="currentColor"
d="M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0zm-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z"
></path>
</svg>
</el-icon>
<span class="loadingText">{{ $t("myCreating.loading") }}</span>
</div>
</div>
</template>
<script setup>
import { useI18n } from "vue-i18n";
const { locale } = useI18n();
const lanChange = ref(locale);
const props = defineProps({
isLoading: {
required: true, //是否必传
},
});
</script>
<style lang="scss" scoped>
.loadingIcon {
position: relative;
width: 100%;
height: 80px;
line-height: 80px;
text-align: center;
transform: scale(2);
> div {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
}
.loadingText {
position: relative;
top: -2px;
left: 4px;
}
}
</style>

+ 5
- 0
src/main.ts Datei anzeigen

@@ -17,6 +17,9 @@ import "element-plus/theme-chalk/dark/css-vars.css";
import "@/styles/index.scss";
import "uno.css";
import "@/styles/my.scss"; // 引入自己定义的样式
// 引入组件
import myLoading from "@/components/myLoading.vue";


const app = createApp(App);
// 全局注册 自定义指令(directive)
@@ -29,3 +32,5 @@ import ElementPlus from "element-plus";
app.use(ElementPlus);

app.use(router).use(i18n).mount("#app");
// 注册全局组件
app.component('myLoading',myLoading)

+ 1
- 0
src/types/components.d.ts Datei anzeigen

@@ -44,6 +44,7 @@ declare module '@vue/runtime-core' {
IEpVideoPlay: typeof import('~icons/ep/video-play')['default']
LangSelect: typeof import('./../components/LangSelect/index.vue')['default']
MultiUpload: typeof import('./../components/Upload/MultiUpload.vue')['default']
MyLoading: typeof import('./../components/myLoading.vue')['default']
Pagination: typeof import('./../components/Pagination/index.vue')['default']
RightPanel: typeof import('./../components/RightPanel/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']


+ 365
- 76
src/views/createVideo/index copy.vue Datei anzeigen

@@ -15,10 +15,15 @@
<el-icon class="icon-edit"><i-ep-edit /></el-icon>
</div>
<!-- 上传按钮 -->
<button class="uploadBtn">
{{ $t("createVideo.reload") }}
<input type="file" @change="changeFile" />
</button>
<div class="btnBox">
<button class="uploadBtn">
{{ $t("createVideo.reselect") }}
<input type="file" @change="lookImg" />
</button>
<button class="uploadBtn" @click="changeFile">
{{ $t("createVideo.sureUpload") }}
</button>
</div>
</el-row>
<!-- 中间展示大图 -->
<div class="bigImg inmiddle">
@@ -34,7 +39,17 @@
</div>
<div class="upload inmiddle">
+
<input type="file" @change="changeFile" />
<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"
/> -->
</div>
<div class="falseImg inmiddle">
<div><div class="icon">×</div></div>
@@ -46,15 +61,41 @@

<!-- 底部 -->
<div class="left-bottom">
<div class="ai">
<div class="aiAvatar"></div>
<div style="margin-left: 20px">Generate By Ai</div>
<div class="tab flex">
<div
class="pointer"
:class="showFace == 0 ? 'tabAvtive' : ''"
@click="ChangeShowFaceList(0)"
>
{{ $t("createVideo.availableMould") }}
</div>
<div
class="pointer"
:class="showFace == 1 ? 'tabAvtive' : ''"
@click="ChangeShowFaceList(1)"
>
{{ $t("createVideo.personalWarehouse") }}
</div>
</div>
<div class="faceList scrolly">
<div class="faceItem" v-for="item in 7" :key="item">
<div class="img"></div>
<!-- <img src="" alt="" /> -->
<p>{{ item }}name</p>
<div class="faceList">
<!-- 上传图片组件 -->
<div v-if="showFace == 1" class="faceItem">
<span class="uploadImg"
>+
<input class="pointer" type="file" @change="lookImg" />
</span>
</div>
<my-loading :isLoading="feceItemLoading"></my-loading>
<!-- face列表 -->
<div
class="faceItem pointer"
@click="setImgUrl(item.material)"
v-for="item in AiFaceList"
:key="item.id"
>
<!-- <div class="img"></div> -->
<img :src="item.material" alt="" />
<p>{{ item.title }}</p>
</div>
</div>
</div>
@@ -64,21 +105,105 @@
<el-tabs type="border-card" class="tabs">
<!-- ----------------------------- 1 -->
<el-tab-pane :label="$t('createVideo.typeScript')">
<div class="card1">111111111111111111</div>
<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
v-model="title"
:rows="15"
type="textarea"
:placeholder="$t('createVideo.aiText')"
/>
<el-icon :size="20">
<Edit />
</el-icon>
</div>
<p>{{ $t("createVideo.languages") }}</p>
<el-select
v-model="language"
placeholder="Select"
style="width: 100%"
>
<el-option
v-for="item in languageOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<p>{{ $t("createVideo.voices") }}</p>
<el-select
v-model="language"
placeholder="Select"
style="width: 100%"
>
<el-option
v-for="item in languageOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<p>{{ $t("createVideo.styles") }}</p>
<el-select
v-model="language"
placeholder="Select"
style="width: 100%"
>
<el-option
v-for="item in languageOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-button type="primary">{{
$t("createVideo.generateVideo")
}}</el-button>
</div>
</el-tab-pane>
<!-- ------------------------ 2 -->
<el-tab-pane :label="$t('createVideo.uploadAudio')">
<div class="card2">
<!-- 录制MP3上传语音 -->
<div class="uploadAudio">
<button @click="startRecording">开始录音</button>
<button @click="stopRecording">停止录音</button>
<button @click="playRecording">播放录音</button>
<div
class="uploadAudio"
:class="audioUrl ? 'uploadAudioAvtion' : ''"
>
<div class="btnBox">
<button
class="pointer"
:disabled="!isRecording"
@click="startRecording"
>
开始录音
</button>
<button
class="pointer"
@click="stopRecording"
:disabled="isRecording"
>
停止录音
</button>
</div>
<!-- <button @click="playRecording">播放录音</button> -->
<audio v-if="audioUrl" controls :src="audioUrl"></audio>
<button v-if="audioUrl" @click="uploadAudio">上传音频</button>
<button v-if="audioUrl" @click="uploadAudio" class="pointer">
上传音频
</button>
</div>
<!-- 上传视频 -->
<div class="uploadVideo">
<div
class="uploadVideo"
style="text-align: center; line-height: 70px"
>
上传视频
<input type="file" ref="fileInput" @change="handleFileChange" />
<video
v-if="videoSrc"
@@ -90,7 +215,7 @@
</div>
</el-tab-pane>
<!-- ----------------------- 3 -->
<el-tab-pane :label="$t('createVideo.aiScript')">
<el-tab-pane v-if="false" :label="$t('createVideo.aiScript')">
<div class="card3">
<div class="text">
<el-input
@@ -158,60 +283,102 @@
</div>
</div>
</template>

<script setup>
import { ref } from "vue";
import { getCurrentInstance } from "vue";
import Recorder from "js-audio-recorder";
import {
personPhotoList,
awsImgUpload,
videoUpload,
saveImgApi,
} from "@/apis/createVideo";

// 获取AI头像
const AiFaceList = ref([]);
const feceItemLoading = ref(false);
function getAiFaceList(pageNum, pageSize) {
feceItemLoading.value = true;
personPhotoList(pageNum, pageSize)
.then((res) => {
AiFaceList.value = res.data.list;
feceItemLoading.value = false;
})
.catch((err) => {
feceItemLoading.value = false;
console.log(err, "err");
});
}
// 选择显示的face列表
const showFace = ref("0");
function ChangeShowFaceList(index) {
showFace.value = index;
}
// 标题
let title = ref("");
const title = ref("");

// 上传图片
let imgUrl = ref("");
function changeFile(e) {
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];
}
// 上传图片
async function changeFile() {
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) {
ElMessage.success("上传成功!");
} else {
ElMessage.error("上传失败!");
}
const res2 = await saveImgApi({ material: res.data.url });
} catch (error) {
ElMessage.error(error);
}
}

// $t在script中的使用

const {
appContext: {
config: { globalProperties },
},
} = getCurrentInstance();
// 点击aifece
function setImgUrl(url) {
imgUrl.value = url;
}

const string = "createVideo.typeScript";
const t = globalProperties.$t(string);
// 录制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(false);
const isRecording = ref(true);
const audioUrl = ref(null);
const audioData = ref("");

const startRecording = async () => {
if (!isRecording.value) {
try {
await recorder.start();
console.log("Recording started");
isRecording.value = true;
} catch (error) {
console.error(error);
}
try {
await recorder.start();
console.log("Recording started");
isRecording.value = false;
} catch (error) {
console.error(error);
}
};

const stopRecording = async () => {
if (isRecording.value) {
try {
const recording = await recorder.stop();
audioUrl.value = URL.createObjectURL(recorder.getWAVBlob());
isRecording.value = false;
} catch (error) {
console.error(error);
}
try {
const recording = await recorder.stop();
audioUrl.value = URL.createObjectURL(recorder.getWAVBlob());
audioData.value = recorder.getWAVBlob();
isRecording.value = true;
} catch (error) {
console.error(error);
}
};

@@ -221,7 +388,17 @@ const playRecording = () => {
audio.play();
}
};
const uploadAudio = () => {};
async function uploadAudio(params) {
let formData = new FormData();
const timestamp = Date.now();
formData.append("file", audioData.value, timestamp + ".mp3");
try {
const res = await videoUpload(formData);
ElMessage.success("上传成功!");
} catch (error) {
ElMessage.error(error);
}
}

// 上传视频功能
const fileInput = ref(null);
@@ -247,12 +424,26 @@ let languageOptions = reactive([
label: "Option2",
},
]);

// $t在script中的使用
const {
appContext: {
config: { globalProperties },
},
} = getCurrentInstance();

const string = "createVideo.typeScript";
const t = globalProperties.$t(string);

onMounted(() => {
getAiFaceList(1, 100);
});
</script>

<style lang="scss" scoped>
.page {
// height: calc(100vh - 84px);
height: 887px;
// height: 1200px;
height: calc(100vh - 80px);
padding: 20px 0 0 40px;
background-color: #fff;
border-radius: 25px 0 0;
@@ -260,7 +451,7 @@ let languageOptions = reactive([

.left {
width: 70%;
height: 100%;
height: 80%;

:deep(.el-input__wrapper) {
border: none;
@@ -280,10 +471,19 @@ let languageOptions = reactive([
&-top {
position: relative;
width: 100%;
height: 65%;
// height: 65%;
height: 600px;

.uploadBtn {
position: relative;
padding: 5px 10px;
margin-left: 10px;
border-radius: 5px;
transition: all 0.3s;
&:hover {
background-color: #000;
color: #fff;
}
}

.bigImg {
@@ -313,7 +513,14 @@ let languageOptions = reactive([
background-color: green;
border-radius: 50%;
}

.el-upload {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}
.upload {
top: 200px;
width: 100px;
@@ -371,17 +578,25 @@ let languageOptions = reactive([
width: 100%;
height: 32%;
margin-top: 10px;

.tab {
padding: 10px;
> div {
margin-right: 20px;
padding: 5px 10px;
transition: all 0.3s;
border-radius: 5px;
&:hover {
background-color: #000;
color: #fff;
}
}
.tabAvtive {
background-color: #000;
color: #fff;
}
}
.ai {
width: 100%;

.aiAvatar {
width: 100px;
height: 100px;
margin-left: 25px;
background-color: pink;
border-radius: 50%;
}
}

.faceList {
@@ -389,23 +604,43 @@ let languageOptions = reactive([
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
height: 130px;
height: 160px;
overflow-y: scroll;
.faceItem {
position: relative;
margin-right: 10px;
margin-bottom: 10px;
width: 150px;
height: 150px;
padding: 0 25px;
line-height: 30px;
line-height: 150px;
text-align: center;

border-radius: 50%;
border: 2px solid #000;
overflow: hidden;
input {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}
.uploadImg {
line-height: 145px;
font-size: 50px;
font-weight: 700;
text-align: center;
}
p {
height: 30px;
}

img {
width: 100%;
}
.img {
width: 100px;
height: 100px;
background-color: green;
border-radius: 50%;
}
}
@@ -425,26 +660,80 @@ let languageOptions = reactive([

.tabs {
height: 100%;
.card1 {
.text {
padding: 10px;
border: 1px solid #000;

.el-button {
float: right;
margin-top: 10px;
}

:deep(.el-textarea__inner) {
resize: none;
box-shadow: none;
}
}

p {
margin: 10px 0;
}

> .el-button {
width: 100%;
height: 50px;
margin-top: 10px;
}
}
.card2 {
padding: 10px;
> div {
position: relative;
margin-top: 10px;
width: 100%;
height: 100px;
border: #000 1px solid;
border-radius: 10px;
background-color: red;
overflow: hidden;
transition: all 0.3s;
box-shadow: #00000026 2px 2px 2px 2px;
&:hover {
transform: translateY(-10px);
box-shadow: #00000026 2px 2px 2px 2px;
}
}
.uploadAudio {
padding: 20px;
margin-bottom: 20px;
height: 70px;
.btnBox {
display: flex;
justify-content: space-between;
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;
&:hover {
background-color: #000;

color: #fff;
}
}
}
.uploadAudioAvtion {
height: 170px;
}
.uploadVideo {
height: 100px;
input {
position: absolute;
width: 100%;


+ 20
- 10
src/views/createVideo/index.vue Datei anzeigen

@@ -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">
@@ -31,7 +31,7 @@
</div>
</div>
<!-- 没有图片时 -->
<div class="left-top" v-show="!imgUrl">
<div class="left-top" v-show="showUploadBtn">
<!-- 中间展示大图 -->
<div class="noImg">
<div class="trueImg inmiddle">
@@ -79,12 +79,15 @@
</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="faceItem pointer"
@click="setImgUrl(item.material)"
@@ -294,13 +297,16 @@ import {

// 获取AI头像
const AiFaceList = ref([]);
const feceItemLoading = ref(false);
function getAiFaceList(pageNum, pageSize) {
feceItemLoading.value = true;
personPhotoList(pageNum, pageSize)
.then((res) => {
AiFaceList.value = res.data.list;
feceItemLoading.value = false;
})
.catch((err) => {
feceItemLoading.value = false;
console.log(err, "err");
});
}
@@ -310,14 +316,17 @@ function ChangeShowFaceList(index) {
showFace.value = index;
}
// 标题
let title = ref("");
const title = ref("");

// 上传图片
let imgUrl = 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];
showUploadBtn.value = false;
}
// 上传图片
async function changeFile() {
@@ -340,6 +349,7 @@ async function changeFile() {

// 点击aifece
function setImgUrl(url) {
showUploadBtn.value = false;
imgUrl.value = url;
}



Laden…
Abbrechen
Speichern