Parcourir la source

账户信息

dev
congzc il y a 2 ans
Parent
révision
033b0f1604
14 fichiers modifiés avec 611 ajouts et 75 suppressions
  1. +25
    -0
      src/apis/myAccount.js
  2. +51
    -0
      src/components/myLoadingIcon.vue
  3. +36
    -26
      src/lang/package/en.ts
  4. +11
    -1
      src/lang/package/zh-cn.ts
  5. +22
    -5
      src/layout/components/Navbar.vue
  6. +2
    -1
      src/main.ts
  7. +10
    -5
      src/store/modules/userInfo.js
  8. +26
    -1
      src/styles/my.scss
  9. +2
    -0
      src/types/components.d.ts
  10. +203
    -9
      src/views/createVideo/index.vue
  11. +3
    -3
      src/views/login/index.vue
  12. +201
    -15
      src/views/myAccount/index.vue
  13. +6
    -5
      src/views/myCreating/index.vue
  14. +13
    -4
      src/views/myStore/index.vue

+ 25
- 0
src/apis/myAccount.js Voir le fichier

@@ -48,4 +48,29 @@ export function useCodeUserApi() {
url: `api/user/getUseCodeUser`, url: `api/user/getUseCodeUser`,
method: 'get' method: 'get'
}) })
}

/**
* @description 修改用户名和头像
* @params
* @returns
*/
export function updUserInfoApi(data) {
return request({
url: `api/user/updUserInfo`,
method: 'post',
data
})
}

/**
* @description 获取用户信息
* @params
* @returns
*/
export function getUserInfoApi() {
return request({
url: `api/user/getUserInfo`,
method: 'get',
})
} }

+ 51
- 0
src/components/myLoadingIcon.vue Voir le fichier

@@ -0,0 +1,51 @@
<template>
<div 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>
</div>
</div>
</template>
<script setup>
import { useI18n } from "vue-i18n";
const { locale } = useI18n();
const lanChange = ref(locale);
const props = defineProps({
isLoading: {
required: false, //是否必传
},
});
</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>

+ 36
- 26
src/lang/package/en.ts Voir le fichier

@@ -4,30 +4,36 @@ export default {
dashboard: "Dashboard", dashboard: "Dashboard",
document: "Document", document: "Document",
}, },

// 公用
public:{
cancel:'Cancel',
confirm:'Confirm',
username:'Username',
avatar:'Avatar',
},
// 登录页面国际化 // 登录页面国际化
login: { login: {
title: "Metavatar-PC", title: "Metavatar-PC",
username: "Username", username: "Username",
email: "E-mail", email: "E-mail",
password: "Password", password: "Password",
confirmPassword: "Confirm Password",
confirmPassword: "Confirm password",
login: "Sign in", login: "Sign in",
register: "Sign up", register: "Sign up",
loginBtn: "Sign in", loginBtn: "Sign in",
registerBtn: "Sign up", registerBtn: "Sign up",
verifyCode: "Verify Code",
verifyCode: "Verify code",
signIn: "Already got an account? Sign in here", signIn: "Already got an account? Sign in here",
signUp: "Don't have an account? Sign up here", signUp: "Don't have an account? Sign up here",
forgetPwd: "I forgot my password", forgetPwd: "I forgot my password",
forgetPwdTitle:'forgot password',
forgetPwdTitle:'Forgot password',
SendEmail:'Send an email', SendEmail:'Send an email',
resetPassword:'Reset password', resetPassword:'Reset password',
setNewPwd:'Set new password', setNewPwd:'Set new password',
newPwd:'new password',
oldPwd:'old password',
confirmNewPwd:'confirm new password',
confirm:'confirm',
newPwd:'New password',
oldPwd:'Old password',
confirmNewPwd:'Confirm new password',
confirm:'Confirm',
gohome:'Back to home page' gohome:'Back to home page'
}, },


@@ -40,26 +46,29 @@ export default {


// 创作视频 // 创作视频
createVideo: { createVideo: {
title: "CreateVideo",
availableMould:"Available Moulds",
title: "Create Video",
availableMould:"Available moulds",
personalWarehouse:'Personal warehouse', personalWarehouse:'Personal warehouse',
typeScript: "Type your Script",
uploadAudio: "Upload Audio",
typeScript: "Type your script",
uploadAudio: "Upload audio",
recordedAudio:'Recorded audio', recordedAudio:'Recorded audio',
startRecorded:'Start recording', startRecorded:'Start recording',
stopRecorded:'Stop recording', stopRecorded:'Stop recording',
aiScript: "Ai Script",
aiScript: "Ai script",
typeTitle: "Type a title", typeTitle: "Type a title",
confirm: "Confirm", confirm: "Confirm",
aiText: "Please input here", aiText: "Please input here",
languages: "Languages", languages: "Languages",
voices: "Voices", voices: "Voices",
styles: "Styles", styles: "Styles",
reselect: "reselect",
reselect: "Reselect",
sureUpload: "Confirm upload", sureUpload: "Confirm upload",
generateVideo: "Generate Video",
saveVideo:'save manuscript',
generateVideo: "Generate video",
saveVideo:'Save manuscript',
select:'Please select', select:'Please select',
music:'Music',
Aipicture:'Ai-generated pictures',
AipictureTip:'Please customize your picture',
}, },


// 我的视频 // 我的视频
@@ -68,28 +77,29 @@ export default {
search: "Search...", search: "Search...",
name: "Name", name: "Name",
date: "Date", date: "Date",
videoTitle: "Video Title:",
videoTitle: "Video title:",
download: "Download", download: "Download",
delete: "Delete", delete: "Delete",
more: "More", more: "More",
loading: "Loading , just a moment", loading: "Loading , just a moment",
noList: "Nothing here. How about making one ?", noList: "Nothing here. How about making one ?",
goCreate: "Go Create !",
manuscript: "manuscript",
goCreate: "Go create !",
manuscript: "Manuscript",
generating: "Generating", generating: "Generating",
generationFailed: "Failed", generationFailed: "Failed",
generationSucceed: "Succeed", generationSucceed: "Succeed",
manuscriptText: "manuscript",
generatingText: "The video is generating, please wait a moment",
manuscriptText: "Manuscript",
generatingText: "The video is generating, Please wait a moment",
generationFailedText: "The video generate is failed, Reason:", generationFailedText: "The video generate is failed, Reason:",
edit:'edit'
edit:'Edit'
}, },


// 个人账户 // 个人账户
account: { account: {
title: "My Account", title: "My Account",
reSetPwd: "Reset Password",
until: "until",
reSetPwd: "Reset password",
editInfo:'Edit personal information',
until: "Until",
getMore: "UPGRADE", getMore: "UPGRADE",
copyCode: "Copy invitation code", copyCode: "Copy invitation code",
saveCode: "Save QR code", saveCode: "Save QR code",
@@ -102,7 +112,7 @@ export default {
failed: "Failed", failed: "Failed",
msg1: "Obtain one video production time", msg1: "Obtain one video production time",
inputCode:'Please enter the invitation code', inputCode:'Please enter the invitation code',
submit:'submit',
submit:'Submit',
noListOrder: "没有数据哦,快去邀请更多人加入我们吧~", noListOrder: "没有数据哦,快去邀请更多人加入我们吧~",
noListInvite: "No data, please invite more people to join us", noListInvite: "No data, please invite more people to join us",
}, },
@@ -128,7 +138,7 @@ export default {
expired: expired:
"Your ticket is expired. You can click the button to resend new email then", "Your ticket is expired. You can click the button to resend new email then",
sendSuccess: "The email has been resent, you can check it now", sendSuccess: "The email has been resent, you can check it now",
goLogin: "Login Now",
goLogin: "Login now",
reSend: "Resend", reSend: "Resend",
}, },
}; };

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

@@ -4,7 +4,13 @@ export default {
dashboard: "首页", dashboard: "首页",
document: "项目文档", document: "项目文档",
}, },

// 公用
public:{
cancel:'取消',
confirm:'确定',
username:'用户名',
avatar:'头像',
},
// 登录页面国际化 // 登录页面国际化
login: { login: {
title: "Metavatar-PC", title: "Metavatar-PC",
@@ -60,6 +66,9 @@ export default {
generateVideo: "生成视频", generateVideo: "生成视频",
saveVideo:'保存草稿', saveVideo:'保存草稿',
select:'请选择', select:'请选择',
music:'音乐',
Aipicture:'Ai生成图片',
AipictureTip:'请自定义您的图片',
}, },


// 我的视频 // 我的视频
@@ -89,6 +98,7 @@ export default {
account: { account: {
title: "个人账户", title: "个人账户",
reSetPwd: "修改密码", reSetPwd: "修改密码",
editInfo:'编辑个人信息',
until: "有效期至", until: "有效期至",
getMore: "升级套餐", getMore: "升级套餐",
copyCode: "复制邀请码", copyCode: "复制邀请码",


+ 22
- 5
src/layout/components/Navbar.vue Voir le fichier

@@ -16,7 +16,13 @@
<!--语言选择--> <!--语言选择-->
<lang-select class="navItem" style="color: #ffffff" /> <lang-select class="navItem" style="color: #ffffff" />


<!-- <div class="avatar" v-if="AccessToken" @click="routerTo"></div> -->
<div
class="avatar"
v-if="userInfoPinia.userInfo.avatarUrl"
@click="routerTo"
>
<img :src="userInfoPinia.userInfo.avatarUrl" alt="" />
</div>
<div class="navItem" v-if="AccessToken" @click="routerTo"> <div class="navItem" v-if="AccessToken" @click="routerTo">
{{ $t("navbar.account") }} {{ $t("navbar.account") }}
</div> </div>
@@ -43,7 +49,8 @@ import { useTagsViewStore } from "@/store/modules/tagsView";
import { useUserStore } from "@/store/modules/user"; import { useUserStore } from "@/store/modules/user";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import LangSelect from "@/components/LangSelect/index.vue"; import LangSelect from "@/components/LangSelect/index.vue";

import { userInfoModules } from "@/store/modules/userInfo";
const userInfoPinia = userInfoModules(); //pinia
const { locale } = useI18n(); const { locale } = useI18n();


// 当前语言状态与国际化组件 // 当前语言状态与国际化组件
@@ -159,13 +166,23 @@ watch(
box-shadow: 0 0 1px #0003; box-shadow: 0 0 1px #0003;
padding-right: 50px; padding-right: 50px;
.avatar { .avatar {
width: 30px;
height: 30px;
position: relative;
width: 50px;
height: 50px;
margin-right: 10px; margin-right: 10px;
margin-left: 20px; margin-left: 20px;
background-color: #4769da;
background-color: #fff;
border-radius: 50%; border-radius: 50%;
cursor: pointer; cursor: pointer;
overflow: hidden;
img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
max-width: 100%;
max-height: 100%;
}
} }
.navItem { .navItem {
cursor: pointer; cursor: pointer;


+ 2
- 1
src/main.ts Voir le fichier

@@ -19,6 +19,7 @@ import "uno.css";
import "@/styles/my.scss"; // 引入自己定义的样式 import "@/styles/my.scss"; // 引入自己定义的样式
// 引入组件 // 引入组件
import myLoading from "@/components/myLoading.vue"; import myLoading from "@/components/myLoading.vue";
import myLoadingIcon from "@/components/myLoadingIcon.vue";




const app = createApp(App); const app = createApp(App);
@@ -33,4 +34,4 @@ app.use(ElementPlus);


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

+ 10
- 5
src/store/modules/userInfo.js Voir le fichier

@@ -1,14 +1,19 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { store } from "@/store"; import { store } from "@/store";
export const userInfoPinia = defineStore("userInfo", () => {
import {
getUserInfoApi,
} from "../../apis/myAccount";
export const userInfoModules = defineStore("userInfo", () => {
// state // state
const email = ref("");
const userInfo = ref(null)
function setEmail(params) { function setEmail(params) {
email.value = params email.value = params
} }
return { email, setEmail };
async function getUserInfo() {
const res = await getUserInfoApi()
userInfo.value = res.data
}
return { userInfo, setEmail, getUserInfo };
}, },
{ {
persist: true, persist: true,

+ 26
- 1
src/styles/my.scss Voir le fichier

@@ -49,4 +49,29 @@ p {
background: linear-gradient(225deg, background: linear-gradient(225deg,
rgb(81 217 202 / 100%), rgb(81 217 202 / 100%),
rgb(114 100 245 / 100%)); rgb(114 100 245 / 100%));
}
}

// 自定义按钮
.customBtn {
padding: 10px 15px;
text-align: center;
background-color: #fff;
color: #000;
transition: all .3s;
border-radius: 15px;
cursor: pointer;

&:hover {
background-color: #000;
color: #fff;
}
}

// element公共样式
.el-dialog {
border-radius: 30px !important;
}

// :deep(.el-input__wrapper.is-focus) {
// box-shadow: 0 0 0 1px #000 !important;
// }

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

@@ -8,6 +8,7 @@ export {}
declare module '@vue/runtime-core' { declare module '@vue/runtime-core' {
export interface GlobalComponents { export interface GlobalComponents {
Breadcrumb: typeof import('./../components/Breadcrumb/index.vue')['default'] Breadcrumb: typeof import('./../components/Breadcrumb/index.vue')['default']
copy: typeof import('./../components/myLoading copy.vue')['default']
ElAlert: typeof import('element-plus/es')['ElAlert'] ElAlert: typeof import('element-plus/es')['ElAlert']
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
@@ -71,6 +72,7 @@ declare module '@vue/runtime-core' {
LangSelect: typeof import('./../components/LangSelect/index.vue')['default'] LangSelect: typeof import('./../components/LangSelect/index.vue')['default']
MultiUpload: typeof import('./../components/Upload/MultiUpload.vue')['default'] MultiUpload: typeof import('./../components/Upload/MultiUpload.vue')['default']
MyLoading: typeof import('./../components/myLoading.vue')['default'] MyLoading: typeof import('./../components/myLoading.vue')['default']
MyLoadingIcon: typeof import('./../components/myLoadingIcon.vue')['default']
Pagination: typeof import('./../components/Pagination/index.vue')['default'] Pagination: typeof import('./../components/Pagination/index.vue')['default']
RightPanel: typeof import('./../components/RightPanel/index.vue')['default'] RightPanel: typeof import('./../components/RightPanel/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']


+ 203
- 9
src/views/createVideo/index.vue Voir le fichier

@@ -124,9 +124,23 @@
<img :src="imgUrl" alt="" class="inmiddle" /> <img :src="imgUrl" alt="" class="inmiddle" />
</div> </div>
</div> </div>
<!-- 选中需要上传的图片前后 -->
<div class="left-top" v-show="showUploadBtn == 5">
<div class="editAiPicBox">
<div class="edit">
<div class="TagBox"></div>
</div>
<div class="AIpicBox">
<div class="picBox">
<img src="../../assets/img/trueImg.png" alt="" />
</div>
</div>
</div>
</div>


<!-- 底部 --> <!-- 底部 -->
<div class="left-bottom"> <div class="left-bottom">
<!-- tab栏 -->
<div class="tab flex"> <div class="tab flex">
<div <div
class="pointer" class="pointer"
@@ -143,6 +157,14 @@
> >
{{ $t("createVideo.personalWarehouse") }} {{ $t("createVideo.personalWarehouse") }}
</div> </div>
<div
v-if="AccessToken"
class="pointer"
:class="showFace == 2 ? 'tabAvtive' : ''"
@click="chooseAiPic"
>
{{ $t("createVideo.Aipicture") }}
</div>
</div> </div>
<!-- 系统相册 --> <!-- 系统相册 -->
<div <div
@@ -202,6 +224,17 @@
</div> </div>
</div> </div>
</div> </div>
<!-- AI生成图片 -->
<div
class="Aipicture"
v-if="showFace == 2"
v-infinite-scroll="loadMoreAiFaceUser"
:infinite-scroll-disabled="overLoadUser"
>
<div class="title">
{{ $t("createVideo.AipictureTip") }}
</div>
</div>
</div> </div>
</div> </div>
<!-- 右侧栏 --> <!-- 右侧栏 -->
@@ -213,7 +246,7 @@
<div class="text"> <div class="text">
<!-- 文本域 --> <!-- 文本域 -->
<el-input <el-input
maxlength="300"
maxlength="3000"
id="textInputId" id="textInputId"
v-model="textareaContent" v-model="textareaContent"
:rows="15" :rows="15"
@@ -313,7 +346,7 @@
<!-- ------------------------ 2 --> <!-- ------------------------ 2 -->
<el-tab-pane :label="$t('createVideo.uploadAudio')"> <el-tab-pane :label="$t('createVideo.uploadAudio')">
<div class="card2"> <div class="card2">
<!-- 上传频 -->
<!-- 上传频 -->
<p> <p>
<el-icon class="icon-VideoCamera"><i-ep-VideoCamera /></el-icon> <el-icon class="icon-VideoCamera"><i-ep-VideoCamera /></el-icon>
{{ $t("createVideo.uploadAudio") }} {{ $t("createVideo.uploadAudio") }}
@@ -352,7 +385,7 @@
</div> </div>
</div> </div>
<div class="AudioBox" v-if="audioUrl"> <div class="AudioBox" v-if="audioUrl">
<audio controls :src="audioUrl"></audio>
<audio controls :src="audioUrl" id="uploadAudio"></audio>
</div> </div>
<!-- 保存视频 --> <!-- 保存视频 -->
<el-button <el-button
@@ -380,7 +413,72 @@
</div> </div>
</el-tab-pane> </el-tab-pane>
<!-- ----------------------- 3 --> <!-- ----------------------- 3 -->
<el-tab-pane v-if="false" :label="$t('createVideo.aiScript')">
<el-tab-pane :label="$t('createVideo.music')">
<div class="card3">
<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>
<!-- ----------------------- 4 -->
<el-tab-pane :label="$t('createVideo.aiScript')">
<div class="card3"> <div class="card3">
<div class="text"> <div class="text">
<el-input <el-input
@@ -448,7 +546,7 @@
</div> </div>
<!-- 试听的mp3 --> <!-- 试听的mp3 -->
<div style="opacity: 0; width: 0"> <div style="opacity: 0; width: 0">
<audio autoplay :src="previewAudioUrl"></audio>
<audio autoplay :src="previewAudioUrl" id="audio"></audio>
</div> </div>
</div> </div>
</template> </template>
@@ -663,6 +761,13 @@ async function changeFile() {
} }
//#endregion --------------------------- //#endregion ---------------------------


//#region AI生成图片
function chooseAiPic() {
showFace.value = 2;
showUploadBtn.value = 5;
}
//#endregion --------------------------

//#region card1的逻辑 //#region card1的逻辑
const textareaContent = ref(""); const textareaContent = ref("");
function insertIcon() { function insertIcon() {
@@ -754,6 +859,7 @@ async function getPreviewAudio() {
); );
} }
previewAudioUrl.value = res.data.data; previewAudioUrl.value = res.data.data;
document.getElementById("audio").play();
} catch (error) { } catch (error) {
ElMessage.error(error); ElMessage.error(error);
} }
@@ -788,6 +894,7 @@ const stopRecording = async () => {
audioUrl.value = URL.createObjectURL(recorder.getWAVBlob()); audioUrl.value = URL.createObjectURL(recorder.getWAVBlob());
audioData.value = recorder.getWAVBlob(); audioData.value = recorder.getWAVBlob();
isRecording.value = true; isRecording.value = true;
console.log(document.getElementById("uploadAudio").duration);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
@@ -831,14 +938,31 @@ async function uploadAudio(isSaveVideo) {
const fileInput = ref(null); const fileInput = ref(null);


let intervalId = null; // 用于存储 setInterval 的返回值 let intervalId = null; // 用于存储 setInterval 的返回值
const uploadAudioTime = ref(null); // 音频时长
const handleFileChange = async () => { const handleFileChange = async () => {
const file = fileInput.value.files[0]; const file = fileInput.value.files[0];

if (file) { if (file) {
const videoUrl = URL.createObjectURL(file); const videoUrl = URL.createObjectURL(file);
audioUrl.value = videoUrl; audioUrl.value = videoUrl;
audioData.value = file; audioData.value = file;
const audio2 = new Audio();
audio2.src = videoUrl;
countAudioTime(audio2);
} }
}; };
// 计算音频的时长
const countAudioTime = async (audio) => {
while (isNaN(audio.duration) || audio.duration === Infinity) {
// 延迟一会 不然网页都卡死
await new Promise((resolve) => setTimeout(resolve, 200));
// 设置随机播放时间,模拟调进度条
audio.currentTime = 10000000 * Math.random();
}
// console.log("音频的总时长:", Math.floor(audio.duration));
uploadAudioTime.value = Math.floor(audio.duration);
};

// 获取视频上传进度 // 获取视频上传进度
const afterSaveAudioId = ref(null); const afterSaveAudioId = ref(null);
async function uploadProgress(videoId, isSaveVideo) { async function uploadProgress(videoId, isSaveVideo) {
@@ -1007,7 +1131,7 @@ onMounted(async () => {
} }


.left { .left {
width: 70%;
width: 68%;
height: 80%; height: 80%;
padding: 20px; padding: 20px;
:deep(.el-input__wrapper) { :deep(.el-input__wrapper) {
@@ -1160,6 +1284,54 @@ onMounted(async () => {
border: 2px solid #000; border: 2px solid #000;
border-radius: 50%; border-radius: 50%;
} }

.editAiPicBox {
position: relative;
display: flex;
width: 100%;
height: 100%;
border: 1px solid #ccc;
background-color: #f1f2f6;
border-radius: 30px;
overflow: hidden;
.edit {
width: 50%;
height: 100%;

background-color: #fff;
.TagBox {
width: 100%;
height: 100%;

border-radius: 0 0 30px 0;
background-color: #f1f2f6;
}
}
.AIpicBox {
position: relative;
width: 50%;
height: 100%;
border-radius: 30px 0 0 0;
background-color: #fff;
.picBox {
position: relative;
width: 100%;
height: 100%;
border-radius: 30px 0 0 0;
background-color: #fff;
img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

max-width: 100%;
max-height: 100%;
border-radius: 30px;
}
}
}
}
} }


&-bottom { &-bottom {
@@ -1197,7 +1369,7 @@ onMounted(async () => {
overflow-y: scroll; overflow-y: scroll;
.faceItem { .faceItem {
position: relative; position: relative;
margin-right: 35px;
margin-right: 30px;
margin-bottom: 35px; margin-bottom: 35px;
width: 150px; width: 150px;
height: 150px; height: 150px;
@@ -1276,11 +1448,33 @@ onMounted(async () => {
} }
} }
} }
.Aipicture {
width: 100%;
height: 180px;
.title {
font-size: 30px;
text-align: center;
line-height: 80px;
background-image: -webkit-linear-gradient(
left,
#4b61dc,
#15d1b8 25%,
#4b61dc 50%,
#15d1b8 75%,
#4b61dc
) !important;
-webkit-text-fill-color: transparent !important;
-webkit-background-clip: text !important;
background-clip: text !important;
-webkit-background-size: 200% 100% !important;
background-size: 200% 100% !important;
}
}
} }
} }


.right { .right {
width: 30%;
width: 32%;
height: 100%; height: 100%;
padding: 30px 30px 20px 30px; padding: 30px 30px 20px 30px;
background-color: #f1f2f6; background-color: #f1f2f6;
@@ -1449,7 +1643,7 @@ onMounted(async () => {
} }


:deep(.el-tabs__item) { :deep(.el-tabs__item) {
width: 34%;
width: 25%;
} }


:deep(.el-tabs__item:hover) { :deep(.el-tabs__item:hover) {


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

@@ -502,7 +502,7 @@ import {
import axios from "axios"; import axios from "axios";
// 状态管理依赖 // 状态管理依赖


import { userInfoPinia } from "@/store/modules/userInfo";
import { userInfoModules } from "@/store/modules/userInfo";


// API依赖 // API依赖
import { import {
@@ -515,7 +515,7 @@ import { useI18n } from "vue-i18n";


const { locale } = useI18n(); const { locale } = useI18n();
const currentLan = ref(locale); const currentLan = ref(locale);
const userInfo = userInfoPinia();
const userInfoPinia = userInfoModules();
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
/** /**
@@ -957,7 +957,7 @@ async function doLogin(data: any) {
// 注册成功将账号密码保存到本地 // 注册成功将账号密码保存到本地
saveInfo(data); saveInfo(data);
isLogining.value = false; isLogining.value = false;
userInfo.setEmail(data.email); //保存邮箱到pinia
userInfoPinia.getUserInfo(); //保存邮箱到pinia
}) })
.catch((err) => { .catch((err) => {
console.log(err, "err"); console.log(err, "err");


+ 201
- 15
src/views/myAccount/index.vue Voir le fichier

@@ -5,16 +5,31 @@
<!-- 头像 --> <!-- 头像 -->
<div class="left-one border flex justify-between flex-wrap"> <div class="left-one border flex justify-between flex-wrap">
<div class="avatar"> <div class="avatar">
<img :src="defaultAvater" alt="" />
<img
:src="
userInfoPinia.userInfo.avatarUrl
? userInfoPinia.userInfo.avatarUrl
: defaultAvater
"
alt=""
/>
</div> </div>
<div class="info"> <div class="info">
<div class="name">OLO</div>
<span>{{ userInfo.email }}</span>
<span
class="password pointer"
@click="router.push({ name: 'login', params: { type: 4 } })"
>{{ $t("account.reSetPwd") }}</span
>
<div class="name" v-if="userInfoPinia.userInfo.name">
{{ userInfoPinia.userInfo.name }}
</div>
<span>{{ userInfoPinia.userInfo.email }}</span>
<div>
<span class="password pointer" @click="showEditInfoDialog = true">{{
$t("account.editInfo")
}}</span>
<span
class="password pointer"
style="margin-right: 10px"
@click="router.push({ name: 'login', params: { type: 4 } })"
>{{ $t("account.reSetPwd") }}</span
>
</div>
</div> </div>
</div> </div>
<!-- 剩余次数 --> <!-- 剩余次数 -->
@@ -134,6 +149,40 @@
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
<!-- 修改个人信息弹窗 -->
<el-dialog
width="30%"
class="editInfoDialog"
v-model="showEditInfoDialog"
:title="$t('account.editInfo')"
destroy-on-close
@close="closeInfoDialog"
>
<el-row>
<el-col :span="4"> {{ $t("public.avatar") }}: </el-col>
<el-col :span="20">
<div class="dialogAvatar">
<input accept="image/*" type="file" @change="chooseImg" />
<div class="add">+</div>
<img v-if="dialogAvatarUrl" :src="dialogAvatarUrl" alt="" />
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="4"> {{ $t("public.username") }}: </el-col>
<el-col :span="20">
<el-input v-model="userNameinput" />
</el-col>
</el-row>
<el-row>
<div class="customBtn" @click="showEditInfoDialog = false">
{{ $t("public.cancel") }}
</div>
<div class="customBtn" @click="submitUserInfo">
{{ $t("public.confirm") }}
</div>
</el-row>
</el-dialog>
</div> </div>
</template> </template>


@@ -141,21 +190,82 @@
//#region 导入文件 //#region 导入文件
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { userInfoPinia } from "@/store/modules/userInfo";
import { userInfoModules } from "@/store/modules/userInfo";
import dayjs from "dayjs"; import dayjs from "dayjs";
import imageCompression from "browser-image-compression"; //压缩图片插件
import { import {
inviteCodeApi, inviteCodeApi,
useCodeApi, useCodeApi,
isUseApi, isUseApi,
useCodeUserApi, useCodeUserApi,
updUserInfoApi,
} from "../../apis/myAccount"; } from "../../apis/myAccount";
import { awsImgUpload } from "@/apis/createVideo";
import defaultAvater from "../../assets/img/left-top-logo.png"; import defaultAvater from "../../assets/img/left-top-logo.png";

//#endregion --------------------------- //#endregion ---------------------------


const { locale } = useI18n(); const { locale } = useI18n();
const lanChange = ref(locale); //国际化 const lanChange = ref(locale); //国际化


const userInfo = userInfoPinia(); //pinia
const userInfoPinia = userInfoModules(); //pinia

//#region 编辑个人信息
const showEditInfoDialog = ref(false); //控制弹窗显隐
const userNameinput = ref(null); //用户名输入框绑定
const dialogAvatarUrl = ref(null); //图片回显地址
const dialogAvatarData = ref(null); //图片上传数据
const infoDialogLoad = ref(false); //load效果
// 选择图片
async function chooseImg(e) {
if (e.target.files[0]) {
dialogAvatarUrl.value = null;
dialogAvatarData.value = null;
// 压缩配置
const options = {
maxSizeMB: 2, // 最大压缩大小为 1MB
useWebWorker: true, // 使用 Web Worker 进行压缩,提高性能
};
const compressedFile = await imageCompression(e.target.files[0], options);
dialogAvatarUrl.value = URL.createObjectURL(compressedFile);
dialogAvatarData.value = compressedFile;
} else {
return;
}
}
// 上传编辑信息
async function submitUserInfo() {
let formData = new FormData();
const timestamp = Date.now();
formData.append("file", dialogAvatarData.value, timestamp + ".png");
const res1 = await awsImgUpload(formData);
const data = {
name: userNameinput.value,
avatarUrl: res1.data.url,
};
try {
const res2 = await updUserInfoApi(data);
ElMessage.success(
lanChange.value == "zh-cn" ? `修改成功` : `Modified successfully`
);
userInfoPinia.getUserInfo();
showEditInfoDialog.value = false;
} catch (error) {
ElMessage.error(
lanChange.value == "zh-cn"
? `修改失败,请稍后重试`
: `The modification failed. Please try again later`
);
}
}
// 关闭弹窗清空
function closeInfoDialog() {
userNameinput.value = userInfoPinia.userInfo.name;
dialogAvatarUrl.value = userInfoPinia.userInfo.avatarUrl;
dialogAvatarData.value = null;
}
//#endregion ---------------------------

//#region 二维码邀请码区域 //#region 二维码邀请码区域
const myInviteCode = ref(null); //我的邀请码 const myInviteCode = ref(null); //我的邀请码
async function getMyInviteCode() { async function getMyInviteCode() {
@@ -168,10 +278,18 @@ function copyInviteCode() {
navigator.clipboard navigator.clipboard
.writeText(inviteCode) .writeText(inviteCode)
.then(() => { .then(() => {
ElMessage.success("邀请码已复制到剪贴板");
ElMessage.success(
lanChange.value == "zh-cn"
? "邀请码已复制到剪贴板"
: `The invitation code has been copied to the clipboard`
);
}) })
.catch((error) => { .catch((error) => {
ElMessage.error("无法复制邀请码:", error);
ElMessage.error(
lanChange.value == "zh-cn"
? "无法复制邀请码:"
: `Unable to copy invitation code`
);
}); });
} }
// 下载二维码图片 // 下载二维码图片
@@ -228,6 +346,8 @@ onMounted(() => {
getMyInviteCode(); // 查询用户的邀请码 getMyInviteCode(); // 查询用户的邀请码
getIsUseState(); //查询是否使用过邀请码 getIsUseState(); //查询是否使用过邀请码
getInviteList(); getInviteList();
userNameinput.value = userInfoPinia.userInfo.name;
dialogAvatarUrl.value = userInfoPinia.userInfo.avatarUrl;
}); });
//#endregion --------------------------- //#endregion ---------------------------


@@ -249,7 +369,7 @@ function routerTo(url) {
} }


.left { .left {
width: 37%;
width: 39%;
height: 100%; height: 100%;


padding: 30px; padding: 30px;
@@ -307,6 +427,7 @@ function routerTo(url) {
&-two { &-two {
position: relative; position: relative;
height: 80px; height: 80px;
overflow: hidden;


.number { .number {
font-size: 30px; font-size: 30px;
@@ -322,12 +443,14 @@ function routerTo(url) {
position: absolute; position: absolute;
top: -1px; top: -1px;
right: -1px; right: -1px;
padding: 5px;
width: 80px; width: 80px;
height: 80px; height: 80px;
line-height: 80px;
line-height: 70px;
text-align: center; text-align: center;
background-color: #000; background-color: #000;
color: #fff; color: #fff;
font-size: 14px;
transition: all 0.3s; transition: all 0.3s;
&:hover { &:hover {
background-color: #15d1b8; background-color: #15d1b8;
@@ -416,7 +539,7 @@ function routerTo(url) {
.right { .right {
background-color: #f1f2f6; background-color: #f1f2f6;
padding: 30px; padding: 30px;
width: 63%;
width: 61%;
height: 100%; height: 100%;
// height: 95%; // height: 95%;
border-radius: 30px 0 0 0; border-radius: 30px 0 0 0;
@@ -567,6 +690,69 @@ function routerTo(url) {
} }
} }


.editInfoDialog {
.el-row {
display: flex;
justify-content: space-evenly;
}
.el-col {
margin-bottom: 10px;
text-align: right;
line-height: 32px;
padding-right: 20px;
}
.dialogAvatar {
position: relative;
width: 200px;
height: 200px;
background-color: rgba(204, 204, 204, 0.2);
border-radius: 30px;
overflow: hidden;
&:hover {
img {
z-index: 0;
}
.add {
background-color: rgba(0, 0, 0, 0.2);
}
}
input {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
z-index: 3;
cursor: pointer;
}
.add {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
text-align: center;
line-height: 200px;
font-size: 50px;
font-weight: 700;
color: #000;
transition: all 0.3s;
}
img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 10px;
max-width: 100%;
max-height: 100%;
z-index: 2;
transition: all 0.3s;
}
}
}
// 公共类名 // 公共类名
.bigWord { .bigWord {
font-size: 30px; font-size: 30px;


+ 6
- 5
src/views/myCreating/index.vue Voir le fichier

@@ -38,7 +38,7 @@


<div class="workInfo flex"> <div class="workInfo flex">
<span>{{ item.title }}</span> <span>{{ item.title }}</span>
<span>{{ item.createDate }}</span>
<span>{{ dayjs(item.createDate).format("YYYY-MM-DD") }}</span>
</div> </div>
<!-- 更多遮罩层 --> <!-- 更多遮罩层 -->
<div <div
@@ -205,7 +205,7 @@ import { timestampToTime } from "@/utils/tools";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { getStatus } from "./videoStatus"; import { getStatus } from "./videoStatus";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import dayjs from "dayjs";
const router = useRouter(); const router = useRouter();
// 当前语言状态与国际化组件 // 当前语言状态与国际化组件
const { locale } = useI18n(); const { locale } = useI18n();
@@ -297,9 +297,9 @@ function getPhotoVideoList(pageNum, pageSize, title, searchFlag) {
.then((res) => { .then((res) => {
console.log(res, "res"); console.log(res, "res");
res.data.list.forEach((item) => { res.data.list.forEach((item) => {
item.createDate = timestampToTime(item.createDate) || "";
item.updateDate = timestampToTime(item.updateDate) || "";
item.createVideoDate = timestampToTime(item.createVideoDate) || "";
// item.createDate = timestampToTime(item.createDate) || "";
// item.updateDate = timestampToTime(item.updateDate) || "";
// item.createVideoDate = timestampToTime(item.createVideoDate) || "";
item.statusName = getStatus(item.videoStatus); item.statusName = getStatus(item.videoStatus);
}); });
videoList.value = res.data.list; videoList.value = res.data.list;
@@ -514,6 +514,7 @@ onMounted(() => {
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
font-size: 13px;
} }
.statusName { .statusName {
position: absolute; position: absolute;


+ 13
- 4
src/views/myStore/index.vue Voir le fichier

@@ -86,7 +86,8 @@
> >
<div class="orderCodeDialog"> <div class="orderCodeDialog">
<div class="codeImg"> <div class="codeImg">
<img src="../../assets/img/false1.png" alt="" />
<my-Loading-Icon v-if="!orderCodeUrl"></my-Loading-Icon>
<img v-if="orderCodeUrl" src="../../assets/img/false1.png" alt="" />
</div> </div>
<div class="tips">扫描二维码进行付款</div> <div class="tips">扫描二维码进行付款</div>
<div class="btnBox"> <div class="btnBox">
@@ -169,7 +170,6 @@ const showPayDialog = ref(false); //套餐信息dialog显示隐藏
const presentItme = reactive({}); //点击的套餐项 const presentItme = reactive({}); //点击的套餐项
function clickPayDialog(item) { function clickPayDialog(item) {
presentItme.value = item; presentItme.value = item;
console.log(presentItme);
showPayDialog.value = true; showPayDialog.value = true;
} }
function showOrderCode(type) { function showOrderCode(type) {
@@ -179,6 +179,7 @@ function showOrderCode(type) {


//#region 点击套餐内的支付 //#region 点击套餐内的支付
const orderCodeDialogShow = ref(false); const orderCodeDialogShow = ref(false);
const orderCodeUrl = ref(null);
//#endregion ------------------------------------ //#endregion ------------------------------------


//#region //#region
@@ -352,10 +353,18 @@ const orderCodeDialogShow = ref(false);
width: 100%; width: 100%;
.codeImg { .codeImg {
display: flex; display: flex;
margin: auto;
justify-content: space-evenly; justify-content: space-evenly;
align-items: center;
width: 300px;
height: 300px;
border: 1px solid #ccc;
border-radius: 15px;
overflow: hidden;
padding: 10px;
img { img {
width: 300px;
height: 300px;
width: 100%;
height: 100%;
} }
} }
.tips { .tips {


Chargement…
Annuler
Enregistrer