congzc il y a 1 an
Parent
révision
bdadad0719
10 fichiers modifiés avec 265 ajouts et 103 suppressions
  1. +32
    -32
      index.html
  2. +4
    -1
      src/lang/package/en.ts
  3. +4
    -1
      src/lang/package/zh-cn.ts
  4. +2
    -1
      src/layout/components/AppMain.vue
  5. +10
    -2
      src/layout/components/Navbar.vue
  6. +1
    -1
      src/layout/components/Sidebar/index.vue
  7. +2
    -0
      src/types/auto-imports.d.ts
  8. +106
    -34
      src/views/createVideo/index.vue
  9. +73
    -27
      src/views/login/index.vue
  10. +31
    -4
      src/views/myAccount/index.vue

+ 32
- 32
index.html Voir le fichier

@@ -21,38 +21,38 @@

<script>
//#region 禁用网页滚动
const keyCodeMap = {
// 91: true, // command
61: true,
107: true, // 数字键盘 +
109: true, // 数字键盘 -
173: true, // 火狐 - 号
187: true, // +
189: true, // -
};
// 覆盖ctrl||command + ‘+’/‘-’
document.onkeydown = function (event) {
const e = event || window.event;
const ctrlKey = e.ctrlKey || e.metaKey;
if (ctrlKey && keyCodeMap[e.keyCode]) {
e.preventDefault();
} else if (e.detail) { // Firefox
event.returnValue = false;
}
};
// 覆盖鼠标滑动
document.body.addEventListener('wheel', (e) => {
if (e.ctrlKey) {
if (e.deltaY < 0) {
e.preventDefault();
return false;
}
if (e.deltaY > 0) {
e.preventDefault();
return false;
}
}
}, { passive: false });
// const keyCodeMap = {
// // 91: true, // command
// 61: true,
// 107: true, // 数字键盘 +
// 109: true, // 数字键盘 -
// 173: true, // 火狐 - 号
// 187: true, // +
// 189: true, // -
// };
// // 覆盖ctrl||command + ‘+’/‘-’
// document.onkeydown = function (event) {
// const e = event || window.event;
// const ctrlKey = e.ctrlKey || e.metaKey;
// if (ctrlKey && keyCodeMap[e.keyCode]) {
// e.preventDefault();
// } else if (e.detail) { // Firefox
// event.returnValue = false;
// }
// };
// // 覆盖鼠标滑动
// document.body.addEventListener('wheel', (e) => {
// if (e.ctrlKey) {
// if (e.deltaY < 0) {
// e.preventDefault();
// return false;
// }
// if (e.deltaY > 0) {
// e.preventDefault();
// return false;
// }
// }
// }, { passive: false });
//#endregion -----------------------------------

//#region


+ 4
- 1
src/lang/package/en.ts Voir le fichier

@@ -41,7 +41,8 @@ export default {
navbar: {
account: "Account",
logout: "Logout",
goLogin:'Go and log in'
goLogin:'Go and log in',
LanguageChange:'Language switching'
},

// 创作视频
@@ -79,6 +80,8 @@ export default {
copy:'Copy to text',
tooltip1:'Click to listen',
tooltip2:'Add Pause',
uploadImgTip1:'Click here to upload pictures',
uploadImgTip2:'Please ensure that the uploaded image is an open face image',
},

// 我的视频


+ 4
- 1
src/lang/package/zh-cn.ts Voir le fichier

@@ -41,7 +41,8 @@ export default {
navbar: {
account: "账户",
logout: "注销",
goLogin:'登录'
goLogin:'登录',
LanguageChange:'语言切换'
},

// 创作视频
@@ -79,6 +80,8 @@ export default {
copy:'复制到文案',
tooltip1:'点击试听',
tooltip2:'添加停顿',
uploadImgTip1:'点此上传图片',
uploadImgTip2:'请确保上传图片为无遮挡的正脸图片',
},

// 我的视频


+ 2
- 1
src/layout/components/AppMain.vue Voir le fichier

@@ -25,7 +25,8 @@ const tagsViewStore = useTagsViewStore();
min-height: calc(100vh - 80px);
// overflow: hidden;
// background-color: var(--el-bg-color-page);
background-color: #000;
// background-color: #000;
background: linear-gradient(to bottom, black 30%, white 70%);
}

.fixed-header + .app-main {


+ 10
- 2
src/layout/components/Navbar.vue Voir le fichier

@@ -14,7 +14,14 @@
{{ $t(routeName as string) }}
</div>
<!--语言选择-->
<lang-select class="navItem" style="color: #ffffff" />
<el-tooltip
class="box-item"
effect="dark"
:content="$t('navbar.LanguageChange')"
placement="top-start"
>
<lang-select class="navItem" style="color: #ffffff" />
</el-tooltip>

<!-- <div
class="avatar"
@@ -196,9 +203,10 @@ watch(
}
}
.navItem {
font-size: 16px;
cursor: pointer;
transition: all 0.3s;
margin-right: 10px;
margin-right: 20px;
&:hover {
color: #4769da;
}


+ 1
- 1
src/layout/components/Sidebar/index.vue Voir le fichier

@@ -25,7 +25,7 @@
<div class="icon">
<el-icon><i-ep-DocumentAdd /></el-icon>
</div>
API Access
{{ $t("API.title") }}
</div>
</div>
</div>


+ 2
- 0
src/types/auto-imports.d.ts Voir le fichier

@@ -2,6 +2,7 @@
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
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 asyncComputed: typeof import('@vueuse/core')['asyncComputed']
@@ -270,6 +271,7 @@ import { UnwrapRef } from 'vue'
declare module 'vue' {
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
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 asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>


+ 106
- 34
src/views/createVideo/index.vue Voir le fichier

@@ -1,7 +1,7 @@
<template>
<div class="page flex justify-around">
<!-- 左侧栏 -->
<div class="left">
<div class="left scrolly">
<!-- 顶部 -->
<!-- 选中AiFace -->
<div class="left-top" v-show="showUploadBtn == 1">
@@ -40,7 +40,11 @@
<div class="icon">✔</div>
</div>
<div v-if="!compressionImgLoad" class="upload inmiddle">
+
<p>
<el-icon><i-ep-FolderAdd /></el-icon>
</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">
@@ -242,7 +246,7 @@
</div>
</div>
<!-- 右侧栏 -->
<div class="right">
<div class="right scrolly">
<div class="subscript">
<!-- <span>GPT</span> -->
<img src="../../assets/img/gpttotext.png" alt="" />
@@ -257,7 +261,7 @@
maxlength="3000"
id="textInputId"
v-model="textareaContent"
:rows="15"
:rows="12"
type="textarea"
:placeholder="$t('createVideo.aiText')"
/>
@@ -380,22 +384,36 @@
<el-icon class="icon-Headset"><i-ep-Headset /></el-icon>
{{ $t("createVideo.uploadAudio") }}
</p>
<div class="uploadVideo">
<div
class="uploadVideo"
:class="
audioUrl && showAudioWhich == 1 ? 'uploadAudioAvtion2' : ''
"
>
<el-icon><i-ep-FolderAdd /></el-icon>
<!-- fileInput.value.files[0] e.target.value = null -->
<input
accept="audio/*"
type="file"
ref="fileInput"
@click="e.target.value = null"
@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") }}
</p>
<div class="uploadAudio">
<div
class="uploadAudio"
:class="
audioUrl && showAudioWhich == 2 ? 'uploadAudioAvtion' : ''
"
>
<div class="btnBox">
<button
class="pointer"
@@ -412,10 +430,13 @@
{{ $t("createVideo.stopRecorded") }}
</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">
<!-- <div class="AudioBox" v-if="audioUrl">
<audio controls :src="audioUrl" id="uploadAudio"></audio>
</div>
</div> -->
<!-- 保存视频 -->
<el-button
@click="saveOrUpdate(2, 'saveVideo')"
@@ -968,7 +989,7 @@ async function getPreviewAudio() {
if (!res.data.data) {
ElMessage.error(
lanChange.value == "zh-cn"
? `暂时无法试听,请稍后重试1`
? `暂时无法试听,请稍后重试`
: `Unable to listen, please try again later`
);
previewAudioLoading.value = false;
@@ -984,7 +1005,7 @@ async function getPreviewAudio() {
} catch (error) {
ElMessage.error(
lanChange.value == "zh-cn"
? `暂时无法试听,请稍后重试2`
? `暂时无法试听,请稍后重试`
: `Unable to listen, please try again later`
);
previewAudioLoading.value = false;
@@ -993,6 +1014,10 @@ async function getPreviewAudio() {
}
//#endregion

//#region card2的逻辑
const showAudioWhich = ref(0); // 哪个音乐控件显示
//#endregion ----------------------------

//#region 录制MP3上传语音
const parameter = {
sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
@@ -1006,6 +1031,11 @@ const audioData = ref("");
const videoId = ref(null); //上传mp3的videoId,创建视频会用到

const startRecording = async () => {
if (showAudioWhich.value != 2) {
audioUrl.value = null;
audioData.value = null;
showAudioWhich.value = 2;
}
try {
await recorder.start();
console.log("Recording started");
@@ -1021,7 +1051,7 @@ const stopRecording = async () => {
audioUrl.value = URL.createObjectURL(recorder.getWAVBlob());
audioData.value = recorder.getWAVBlob();
isRecording.value = true;
console.log(document.getElementById("uploadAudio").duration);
// console.log(document.getElementById("uploadAudio").duration);
} catch (error) {
console.error(error);
}
@@ -1066,7 +1096,17 @@ const fileInput = ref(null);

let intervalId = null; // 用于存储 setInterval 的返回值
const uploadAudioTime = ref(null); // 音频时长
// 点击上传input
function handleFileClick(e) {
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) {
@@ -1076,7 +1116,7 @@ const handleFileChange = async () => {
// 进行大小时长限制
await countAudioTime(audio2);
// 限制60秒
if (uploadAudioTime.value > 60) {
if (uploadAudioTime.value > 960) {
ElMessage.error(
lanChange.value == "zh-cn"
? `上传失败,您上传的文件时长与您的权益不匹配`
@@ -1087,7 +1127,7 @@ const handleFileChange = async () => {
return;
}
// 限制3mb
if (file.size / 1048576 > 3) {
if (file.size / 1048576 > 93) {
ElMessage.error(
lanChange.value == "zh-cn"
? `上传失败,您上传的文件大小与您的权益不匹配`
@@ -1619,8 +1659,8 @@ onUnmounted(() => {
<style lang="scss" scoped>
.page {
// height: 1000px;
height: calc(100vh - 80px);
height: 1000px;
height: calc(100vh - 80px);
// padding: 20px 0 0 40px;
background-color: #fff;
border-radius: 25px 0 0;
@@ -1630,7 +1670,10 @@ onUnmounted(() => {
width: 68%;
// height: 860px;
height: 1000px;
max-height: 100%;
padding: 20px;
overflow: hidden;
overflow-y: scroll;
:deep(.el-input__wrapper) {
border: none;
border-bottom: 2px solid #000;
@@ -1704,7 +1747,7 @@ onUnmounted(() => {
}
.trueImg {
position: relative;
top: 60px;
top: 4%;
width: 100px;
height: 100px;
border-radius: 50%;
@@ -1725,18 +1768,41 @@ onUnmounted(() => {
opacity: 0;
}
.upload {
top: 200px;
width: 100px;
height: 100px;
top: 30%;
width: 400px;
height: 200px;
padding-top: 10px;
font-size: 50px;
line-height: 100px;
text-align: center;
background-color: #ccc;
border-radius: 50%;
border-radius: 30px;
box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 5px 5px;
p {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: -1;
opacity: 0.1;
.el-icon {
width: 200px;
height: 200px;
font-size: 150px;
}
}
span {
display: block;
font-size: 16px;
font-weight: 900;
line-height: 16px;
text-align: center;
margin-bottom: 130px;
}
}

.falseImg {
top: 350px;
top: 75%;
// background-color: #795562;
display: flex;
justify-content: space-evenly;
@@ -1864,7 +1930,7 @@ onUnmounted(() => {
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
height: 180px;
height: 220px;
overflow-y: scroll;
.faceItem {
position: relative;
@@ -2040,12 +2106,14 @@ onUnmounted(() => {
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;
.subscript {
position: absolute;
top: 30px;
@@ -2083,7 +2151,7 @@ onUnmounted(() => {
min-height: 100%;
padding: 20px 20px 0px 20px;
border-radius: 20px;
overflow-y: scroll;
.card1 {
.text {
padding: 10px;
@@ -2138,8 +2206,10 @@ onUnmounted(() => {
.card2 {
padding: 10px;
.el-icon {
flex: 1;
// color: red;
vertical-align: text-top;
transition: all 0.3s;
}
> div {
position: relative;
@@ -2154,6 +2224,7 @@ onUnmounted(() => {
transform: translateY(-10px);
}
}
// 录制mp3部分
.uploadAudio {
padding: 20px;
// margin-top: 30px;
@@ -2186,34 +2257,35 @@ onUnmounted(() => {
.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;
input {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
height: 100px;
opacity: 0;
}
video {
position: absolute;
top: 0;
left: 0;
z-index: -1;
width: 100%;
height: 100%;
cursor: pointer;
}
}
.AudioBox {
display: flex;
justify-content: space-around;
padding: 20px;
padding: 10px;
transition: all 0.3s;
}
> .el-button {


+ 73
- 27
src/views/login/index.vue Voir le fichier

@@ -17,15 +17,22 @@
:rules="loginRules"
class="login-form"
>
<div class="flex text-white items-center py-4">
<span class="text-2xl flex-1 text-center">{{
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.login")
}}</span>
<lang-select style="color: #fff" />
<el-tooltip
class="box-item"
effect="dark"
:content="$t('navbar.LanguageChange')"
placement="top-start"
>
<lang-select class="navItem" style="color: #ffffff" />
</el-tooltip>
</div>

<el-form-item prop="email">
<div class="p-2 text-white">
<div class="text-white">
<svg-icon icon-class="user" />
</div>
<el-input
@@ -39,7 +46,7 @@
</el-form-item>

<el-form-item prop="password">
<span class="p-2 text-white">
<span class="text-white">
<svg-icon icon-class="password" />
</span>
<el-input
@@ -61,7 +68,7 @@

<!-- 验证码 -->
<el-form-item prop="verifyCode">
<span class="p-2 text-white">
<span class="text-white">
<svg-icon icon-class="verify_code" />
</span>
<el-input
@@ -122,15 +129,22 @@
:rules="loginRules"
class="login-form"
>
<div class="flex text-white items-center py-4">
<span class="text-2xl flex-1 text-center">{{
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.register")
}}</span>
<lang-select style="color: #fff" />
<el-tooltip
class="box-item"
effect="dark"
:content="$t('navbar.LanguageChange')"
placement="top-start"
>
<lang-select class="navItem" style="color: #ffffff" />
</el-tooltip>
</div>

<el-form-item prop="email">
<div class="p-2 text-white">
<div class="text-white">
<svg-icon icon-class="user" />
</div>
<el-input
@@ -144,7 +158,7 @@
</el-form-item>

<el-form-item prop="password">
<span class="p-2 text-white">
<span class="text-white">
<svg-icon icon-class="password" />
</span>
<el-input
@@ -164,7 +178,7 @@
</el-form-item>

<el-form-item prop="confirmPassword">
<span class="p-2 text-white">
<span class="text-white">
<svg-icon icon-class="password" />
</span>
<el-input
@@ -229,15 +243,22 @@
:rules="loginRules"
class="login-form"
>
<div class="flex text-white items-center py-4">
<span class="text-2xl flex-1 text-center">{{
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.forgetPwdTitle")
}}</span>
<lang-select style="color: #fff" />
<el-tooltip
class="box-item"
effect="dark"
:content="$t('navbar.LanguageChange')"
placement="top-start"
>
<lang-select class="navItem" style="color: #ffffff" />
</el-tooltip>
</div>

<el-form-item prop="email">
<div class="p-2 text-white">
<div class="text-white">
<svg-icon icon-class="user" />
</div>
<el-input
@@ -290,15 +311,22 @@
:rules="loginRules"
class="login-form"
>
<div class="flex text-white items-center py-4">
<span class="text-2xl flex-1 text-center">{{
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.resetPassword")
}}</span>
<lang-select style="color: #fff" />
<el-tooltip
class="box-item"
effect="dark"
:content="$t('navbar.LanguageChange')"
placement="top-start"
>
<lang-select class="navItem" style="color: #ffffff" />
</el-tooltip>
</div>

<el-form-item prop="oldPassword">
<span class="p-2 text-white">
<span class="text-white">
<svg-icon icon-class="password" />
</span>
<el-input
@@ -318,7 +346,7 @@
</el-form-item>

<el-form-item prop="password">
<span class="p-2 text-white">
<span class="text-white">
<svg-icon icon-class="password" />
</span>
<el-input
@@ -338,7 +366,7 @@
</el-form-item>

<el-form-item prop="confirmPassword4">
<span class="p-2 text-white">
<span class="text-white">
<svg-icon icon-class="password" />
</span>
<el-input
@@ -404,15 +432,22 @@
:rules="loginRules"
class="login-form"
>
<div class="flex text-white items-center py-4">
<span class="text-2xl flex-1 text-center">{{
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.setNewPwd")
}}</span>
<lang-select style="color: #fff" />
<el-tooltip
class="box-item"
effect="dark"
:content="$t('navbar.LanguageChange')"
placement="top-start"
>
<lang-select class="navItem" style="color: #ffffff" />
</el-tooltip>
</div>

<el-form-item prop="newPwd">
<div class="p-2 text-white">
<div class="text-white">
<svg-icon icon-class="password" />
</div>
<el-input
@@ -432,7 +467,7 @@
</span>
</el-form-item>
<el-form-item prop="confirmNewPwd">
<div class="p-2 text-white">
<div class="text-white">
<svg-icon icon-class="password" />
</div>
<el-input
@@ -1019,6 +1054,8 @@ onMounted(() => {
.login-container {
position: relative;
width: 100%;
// width: 1920px;
// height: 1080px;
min-height: 100%;
overflow: hidden;
// background-color: #2d3a4b;
@@ -1063,6 +1100,15 @@ onMounted(() => {
&:hover {
backdrop-filter: blur(7px);
}
.items-center {
padding: 20px;
font-size: 30px;
}
.el-form-item {
.text-white {
padding: 8px;
}
}
}
}



+ 31
- 4
src/views/myAccount/index.vue Voir le fichier

@@ -169,6 +169,9 @@
destroy-on-close
@close="closeInfoDialog"
>
<div class="LoadingBox" v-if="submitUserInfoLoading">
<my-Loading-Icon v-if="submitUserInfoLoading"></my-Loading-Icon>
</div>
<el-row>
<el-col :span="4"> {{ $t("public.avatar") }}: </el-col>
<el-col :span="20">
@@ -242,18 +245,23 @@ async function chooseImg(e) {
dialogAvatarData.value = null;
// 压缩配置
const options = {
maxSizeMB: 2, // 最大压缩大小为 1MB
useWebWorker: true, // 使用 Web Worker 进行压缩,提高性能
maxSizeMB: 2, // 最大压缩大小为 2MB
useWebWorker: false, // 使用 Web Worker 进行压缩,提高性能
};
const compressedFile = await imageCompression(e.target.files[0], options);
dialogAvatarUrl.value = URL.createObjectURL(compressedFile);
dialogAvatarData.value = compressedFile;
// 不压缩图片
// dialogAvatarUrl.value = e.target.files[0];
// dialogAvatarData.value = e.target.files[0];
} else {
return;
}
}
const submitUserInfoLoading = ref(false);
// 上传编辑信息
async function submitUserInfo() {
submitUserInfoLoading.value = true;
if (dialogAvatarData.value) {
let formData = new FormData();
const timestamp = Date.now();
@@ -270,6 +278,7 @@ async function submitUserInfo() {
);
await userInfoPinia.getUserInfo();
showEditInfoDialog.value = false;
submitUserInfoLoading.value = false;
router.go(0);
} catch (error) {
ElMessage.error(
@@ -277,6 +286,7 @@ async function submitUserInfo() {
? `修改失败,请稍后重试`
: `The modification failed. Please try again later`
);
submitUserInfoLoading.value = false;
}
} else {
const data = {
@@ -289,6 +299,7 @@ async function submitUserInfo() {
);
await userInfoPinia.getUserInfo();
showEditInfoDialog.value = false;
submitUserInfoLoading.value = false;
router.go(0);
} catch (error) {
ElMessage.error(
@@ -296,6 +307,7 @@ async function submitUserInfo() {
? `修改失败,请稍后重试`
: `The modification failed. Please try again later`
);
submitUserInfoLoading.value = false;
}
}
}
@@ -453,8 +465,9 @@ function routerTo(url) {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
max-width: 100%;
max-height: 100%;
width: 100%;
height: 100%;
object-fit: cover;
}
}

@@ -800,6 +813,20 @@ function routerTo(url) {
}

.editInfoDialog {
position: relative;
overflow: hidden;
.LoadingBox {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999;
opacity: 0.8;
border-radius: 30px;
padding-top: 150px;
background-color: #ccc;
}
.el-row {
display: flex;
justify-content: space-evenly;


Chargement…
Annuler
Enregistrer