| @@ -42,7 +42,7 @@ const props = defineProps({ | |||
| height: 80px; | |||
| line-height: 80px; | |||
| text-align: center; | |||
| transform: scale(2); | |||
| transform: scale(1); | |||
| > div { | |||
| position: absolute; | |||
| top: 0; | |||
| @@ -53,6 +53,7 @@ const props = defineProps({ | |||
| position: relative; | |||
| top: -2px; | |||
| left: 4px; | |||
| font-size: 13px !important; | |||
| } | |||
| } | |||
| </style> | |||
| @@ -0,0 +1,59 @@ | |||
| <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" | |||
| ><span v-if="tips">{{ $t(`myCreating.${tips}`) }},</span | |||
| >{{ $t("createVideo.saveVideo") }}</span | |||
| > | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script setup> | |||
| import { useI18n } from "vue-i18n"; | |||
| const { locale } = useI18n(); | |||
| const lanChange = ref(locale); | |||
| const props = defineProps({ | |||
| isLoading: { | |||
| required: true, //是否必传 | |||
| }, | |||
| tips: { | |||
| required: false, //是否必传 | |||
| }, | |||
| }); | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .loadingIcon { | |||
| position: relative; | |||
| width: 100%; | |||
| height: 80px; | |||
| line-height: 80px; | |||
| text-align: center; | |||
| transform: scale(1); | |||
| > div { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 50%; | |||
| transform: translateX(-50%); | |||
| } | |||
| .loadingText { | |||
| position: relative; | |||
| top: -2px; | |||
| left: 4px; | |||
| font-size: 13px !important; | |||
| } | |||
| } | |||
| </style> | |||
| @@ -15,7 +15,7 @@ export default { | |||
| login: { | |||
| title: "Metavatar-PC", | |||
| username: "Username", | |||
| email: "E-mail", | |||
| email: "E-mail/Phone", | |||
| password: "Password", | |||
| confirmPassword: "Confirm Password", | |||
| login: "Sign In", | |||
| @@ -27,7 +27,7 @@ export default { | |||
| signUp: "Don't have an account? Sign up here", | |||
| forgetPwd: "I forgot my password", | |||
| forgetPwdTitle:'Forgot Password', | |||
| SendEmail:'Send an email', | |||
| SendEmail:'Send an email/SMS', | |||
| resetPassword:'Reset Password', | |||
| setNewPwd:'Set new password', | |||
| newPwd:'New Password', | |||
| @@ -36,6 +36,10 @@ export default { | |||
| confirm:'Confirm', | |||
| gohome:'Back to home page', | |||
| SMSCode:'SMS Code', | |||
| sendSMS:'Send SMS', | |||
| loginByPhone:"SMS login", | |||
| loginByEmail:"E-mail login", | |||
| phone:"phone", | |||
| }, | |||
| // 导航栏国际化 | |||
| @@ -69,7 +73,7 @@ export default { | |||
| saveVideo:'Save Manuscript', | |||
| select:'Please Select', | |||
| music:'Music', | |||
| Aipicture:'AI-generated Pictures', | |||
| Aipicture:'AI-Portrait', | |||
| AipictureTip:'Please customize your picture', | |||
| chooseMusic:'Choose Music', | |||
| searchMusic:'Search Music', | |||
| @@ -15,7 +15,7 @@ export default { | |||
| login: { | |||
| title: "Metavatar-PC", | |||
| username: "用户名", | |||
| email: "电子邮件", | |||
| email: "电子邮件/手机号", | |||
| password: "密码", | |||
| confirmPassword: "确认密码", | |||
| login: "登录", | |||
| @@ -27,7 +27,7 @@ export default { | |||
| signUp: "没有账号?现在加入!", | |||
| forgetPwd: "忘记密码", | |||
| forgetPwdTitle:'忘记密码', | |||
| SendEmail:'发送邮件', | |||
| SendEmail:'发送邮件/短信', | |||
| resetPassword:'重置密码', | |||
| setNewPwd:'设置新密码', | |||
| newPwd:'新密码', | |||
| @@ -36,6 +36,10 @@ export default { | |||
| confirm:'确定', | |||
| gohome:'回到首页', | |||
| SMSCode:'短信验证码', | |||
| sendSMS:'发送短信验证码', | |||
| loginByPhone:"验证码登录", | |||
| loginByEmail:"邮箱登录", | |||
| phone:"手机号", | |||
| }, | |||
| // 导航栏国际化 | |||
| @@ -69,7 +73,7 @@ export default { | |||
| saveVideo:'保存草稿', | |||
| select:'请选择', | |||
| music:'音乐', | |||
| Aipicture:'AI生成图片', | |||
| Aipicture:'AI人像', | |||
| AipictureTip:'请自定义您的图片', | |||
| chooseMusic:'选择音乐', | |||
| searchMusic:'搜索音乐', | |||
| @@ -8,6 +8,7 @@ export {} | |||
| declare module '@vue/runtime-core' { | |||
| export interface GlobalComponents { | |||
| Breadcrumb: typeof import('./../components/Breadcrumb/index.vue')['default'] | |||
| copy: typeof import('./../components/myLoading copy.vue')['default'] | |||
| ElAlert: typeof import('element-plus/es')['ElAlert'] | |||
| ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] | |||
| ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] | |||
| @@ -77,6 +78,7 @@ declare module '@vue/runtime-core' { | |||
| LangSelect: typeof import('./../components/LangSelect/index.vue')['default'] | |||
| MultiUpload: typeof import('./../components/Upload/MultiUpload.vue')['default'] | |||
| MyLoading: typeof import('./../components/myLoading.vue')['default'] | |||
| MyLoading2: typeof import('./../components/myLoading2.vue')['default'] | |||
| MyLoadingIcon: typeof import('./../components/myLoadingIcon.vue')['default'] | |||
| Pagination: typeof import('./../components/Pagination/index.vue')['default'] | |||
| RightPanel: typeof import('./../components/RightPanel/index.vue')['default'] | |||
| @@ -31,17 +31,17 @@ | |||
| /> | |||
| </el-select></div> | |||
| <!-- Y轴 --> | |||
| <div v-show="false" class="item">{{$t('createVideo.YAxis')}}: <el-input | |||
| <div class="item">{{$t('createVideo.YAxis')}}: <el-input | |||
| v-model="SubtitlesTop" | |||
| width="30" | |||
| /></div> | |||
| <!-- X轴 --> | |||
| <div v-show="false" class="item" style="">{{$t('createVideo.XAxis')}}: <el-input | |||
| <div class="item" style="">{{$t('createVideo.XAxis')}}: <el-input | |||
| v-model="SubtitlesLeft" | |||
| width="30" | |||
| /></div> | |||
| <!-- 单双行 --> | |||
| <div class="item" >{{$t('createVideo.rows')}}: <el-switch | |||
| <div v-show="false" class="item" >{{$t('createVideo.rows')}}: <el-switch | |||
| v-model="SubtitlesRow" | |||
| inline-prompt | |||
| style="--el-switch-on-color: #000; --el-switch-off-color: #13ce66;" | |||
| @@ -458,8 +458,8 @@ | |||
| color="#000" | |||
| type="primary" | |||
| > | |||
| <my-loading :isLoading="createLoading"></my-loading> | |||
| <span v-if="!createLoading">{{ | |||
| <my-loading2 :isLoading="saveLoading"></my-loading2> | |||
| <span v-if="!saveLoading">{{ | |||
| $t("createVideo.saveVideo") | |||
| }}</span></el-button | |||
| > | |||
| @@ -577,8 +577,8 @@ | |||
| color="#000" | |||
| type="primary" | |||
| > | |||
| <my-loading :isLoading="createLoading"></my-loading> | |||
| <span v-if="!createLoading">{{ | |||
| <my-loading2 :isLoading="saveLoading"></my-loading2> | |||
| <span v-if="!saveLoading">{{ | |||
| $t("createVideo.saveVideo") | |||
| }}</span></el-button | |||
| > | |||
| @@ -599,7 +599,6 @@ | |||
| <!-- ----------------------- 3 --> | |||
| <el-tab-pane :label="$t('createVideo.music')"> | |||
| <div class="card3"> | |||
| <!-- 选择音乐 --> | |||
| <p> | |||
| <el-icon class="icon-Headset"><i-ep-Headset /></el-icon> | |||
| @@ -717,8 +716,8 @@ | |||
| color="#000" | |||
| type="primary" | |||
| > | |||
| <my-loading :isLoading="createLoading"></my-loading> | |||
| <span v-if="!createLoading">{{ | |||
| <my-loading2 :isLoading="saveLoading"></my-loading2> | |||
| <span v-if="!saveLoading">{{ | |||
| $t("createVideo.saveVideo") | |||
| }}</span></el-button | |||
| > | |||
| @@ -1339,7 +1338,11 @@ const playRecording = () => { | |||
| }; | |||
| // 上传音频 | |||
| async function uploadAudio(isSaveVideo) { | |||
| createLoading.value = true; | |||
| if(isSaveVideo == "saveVideo") { | |||
| saveLoading.value = true; | |||
| } else { | |||
| createLoading.value = true; | |||
| } | |||
| let formData = new FormData(); | |||
| const timestamp = Date.now(); | |||
| formData.append("file", audioData.value, timestamp + ".mp3"); | |||
| @@ -1455,16 +1458,18 @@ async function uploadProgress(videoId, isSaveVideo) { | |||
| speakTypeStr: soundStyle.value, //声音风格 | |||
| voiceMouldId: sound.value, //选择声音id voiceFrom=1 时必传 | |||
| voiceMaterialId: afterSaveAudioId.value, //上传音频且保存音频后得到的id voiceFrom=2 时必传 | |||
| // subtitleEnabled:SubtitlesSwitch.value?1:0 , //字幕开关 | |||
| // subtitleParams:{ | |||
| // Fontname:SubtitlesFontFamily.value, | |||
| // Fontsize:SubtitlesSize.value, | |||
| // Boxwidth:SubtitlesWidth.value, | |||
| // // Boxheight:Number(SubtitlesSize.value+10), | |||
| // Boxheight:SubtitlesBox.value.style.height, | |||
| // SecondaryColour:SubtitlesColorBGRA.value, | |||
| // Marginl:SubtitlesLeft.value, | |||
| // } | |||
| subtitleEnabled:SubtitlesSwitch.value?1:0 , //字幕开关 | |||
| subtitleParams:{ | |||
| Fontname:SubtitlesFontFamily.value, //字体名字 | |||
| Fontsize:SubtitlesSize.value, //字体大小 | |||
| Boxwidth:SubtitlesWidth.value, //字幕宽 | |||
| Boxheight:Number(SubtitlesSize.value+10), //字幕高 | |||
| // Boxheight:SubtitlesBox.value.style.height, | |||
| Marginl:SubtitlesLeft.value, //左边距 | |||
| Marginy:SubtitlesTop.value, //上边距 | |||
| SecondaryColour:rgbaToBgra(SubtitlesColor.value), //字色 | |||
| OutlineColour:rgbaToBgra(SubtitlesBgc.value), //背景色 | |||
| } | |||
| }; | |||
| try { | |||
| const res3 = await saveOrUpdateApi(saveOrUpdateData); // 保存数据 | |||
| @@ -1474,6 +1479,7 @@ async function uploadProgress(videoId, isSaveVideo) { | |||
| lanChange.value == "zh-cn" ? `已保存为草稿` : `Saved as manuscript` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| router.push("/myCreating"); | |||
| return; | |||
| } | |||
| @@ -1493,10 +1499,12 @@ async function uploadProgress(videoId, isSaveVideo) { | |||
| ); | |||
| } | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| router.push("/myCreating"); | |||
| } catch (error) { | |||
| ElMessage.error(error); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| } | |||
| } | |||
| } | |||
| @@ -1506,13 +1514,23 @@ async function uploadProgress(videoId, isSaveVideo) { | |||
| // tab栏切换 | |||
| const tabFrom = ref(1); | |||
| const createLoading = ref(false); | |||
| const saveLoading = ref(false); | |||
| // 上传音频后,得到videoId | |||
| // 保存数据 | |||
| async function saveOrUpdate(index, isSaveVideo) { | |||
| if (saveLoading.value == true) { | |||
| ElMessage.error(lanChange.value == "zh-cn" ? `正在保存` : `Be saving`); | |||
| return; | |||
| } | |||
| if (createLoading.value == true) { | |||
| ElMessage.error(lanChange.value == "zh-cn" ? `正在生成` : `Be generating`); | |||
| return; | |||
| } | |||
| if(isSaveVideo == "saveVideo") { | |||
| saveLoading.value = true | |||
| } else { | |||
| createLoading.value = true | |||
| } | |||
| tabFrom.value = index; // 判断是哪一个tab栏内的生成视频按钮 | |||
| const saveOrUpdateData = { | |||
| id: id.value, //从草稿或者重新编辑回到创建视频时有id | |||
| @@ -1524,14 +1542,26 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| voiceMouldId: sound.value, //选择声音id voiceFrom=1 时必传 | |||
| voiceMaterialId: afterSaveAudioId.value, //上传音频且保存音频后得到的id voiceFrom=2 时必传 | |||
| musicId: musicItemAction.value, // 选中音乐的id,voiceFrom=3 时必传 | |||
| subtitleEnabled:SubtitlesSwitch.value?1:0 , //字幕开关 | |||
| subtitleParams:JSON.stringify({ | |||
| Fontname:SubtitlesFontFamily.value, //字体名字 | |||
| Fontsize:SubtitlesSize.value, //字体大小 | |||
| Boxwidth:SubtitlesWidth.value, //字幕宽 | |||
| Boxheight:Number(SubtitlesSize.value+10), //字幕高 | |||
| // Boxheight:SubtitlesBox.value.style.height, | |||
| Marginl:SubtitlesLeft.value, //左边距 | |||
| Marginy:SubtitlesTop.value, //上边距 | |||
| SecondaryColour:rgbaToBgra(SubtitlesColor.value), //字色 | |||
| OutlineColour:rgbaToBgra(SubtitlesBgc.value), //背景色 | |||
| }) | |||
| }; | |||
| if (index == 1) { | |||
| createLoading.value = true; | |||
| if (!saveOrUpdateData.personPhotoId) { | |||
| ElMessage.error( | |||
| lanChange.value == "zh-cn" ? `请选择图片` : `Please select a picture` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| return; | |||
| } | |||
| if (!saveOrUpdateData.paperwork) { | |||
| @@ -1539,6 +1569,7 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| lanChange.value == "zh-cn" ? `请输入文案` : `Please enter copy` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| return; | |||
| } | |||
| if (!saveOrUpdateData.voiceMouldId) { | |||
| @@ -1546,6 +1577,7 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| lanChange.value == "zh-cn" ? `请选择声音` : `Please select sound` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| return; | |||
| } | |||
| try { | |||
| @@ -1562,6 +1594,7 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| : `Video duration estimation failed, can not generate video, you can try to change the sound` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| return; | |||
| } | |||
| if (res4.data.data > 60) { | |||
| @@ -1575,6 +1608,7 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| )} long, and the free user-generated video is 60 seconds long and cannot be generated` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| return; | |||
| } | |||
| ElMessage.success( | |||
| @@ -1593,6 +1627,7 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| lanChange.value == "zh-cn" ? `已保存为草稿` : `Saved as manuscript` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| router.push("/myCreating"); | |||
| return; | |||
| } | |||
| @@ -1608,12 +1643,14 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| ); | |||
| } | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| router.push("/myCreating"); | |||
| }, 3000); | |||
| } catch (error) { | |||
| // ElMessage.error($t(error.message)); | |||
| ElMessage.error(error); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| } | |||
| } | |||
| if (index == 2) { | |||
| @@ -1622,6 +1659,7 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| lanChange.value == "zh-cn" ? `请选择图片` : `Please select a picture` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| return; | |||
| } | |||
| if (!audioData.value && !afterSaveAudioId.value) { | |||
| @@ -1633,6 +1671,7 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| : `Please select an audio file` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| return; | |||
| } | |||
| try { | |||
| @@ -1645,16 +1684,17 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| : `Generation failed, please re-select the audio` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| } | |||
| } | |||
| if (index == 3) { | |||
| createLoading.value = true; | |||
| try { | |||
| if (!saveOrUpdateData.personPhotoId) { | |||
| ElMessage.error( | |||
| lanChange.value == "zh-cn" ? `请选择图片` : `Please select a picture` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| return; | |||
| } | |||
| if (!saveOrUpdateData.musicId) { | |||
| @@ -1664,6 +1704,7 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| : `Please select an music file` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| return; | |||
| } | |||
| const res1 = await saveOrUpdateApi(saveOrUpdateData); // 保存数据 | |||
| @@ -1674,6 +1715,7 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| lanChange.value == "zh-cn" ? `已保存为草稿` : `Saved as manuscript` | |||
| ); | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| router.push("/myCreating"); | |||
| return; | |||
| } | |||
| @@ -1694,6 +1736,7 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| ); | |||
| } | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| router.push("/myCreating"); | |||
| } catch (error) { | |||
| if (error) { | |||
| @@ -1706,6 +1749,7 @@ async function saveOrUpdate(index, isSaveVideo) { | |||
| ); | |||
| } | |||
| createLoading.value = false; | |||
| saveLoading.value = false; | |||
| } | |||
| } | |||
| } | |||
| @@ -1744,6 +1788,21 @@ async function findById(findId) { | |||
| sound.value = res.data.voiceMouldId; //声音id | |||
| chooseStyle(); | |||
| soundStyle.value = res.data.speakTypeStr; //选择风格 | |||
| // 以下为字幕信息 | |||
| SubtitlesSwitch.value=res.data.subtitleEnabled==1?true:false | |||
| const subtitleParamsToObj=JSON.parse(res.data.subtitleParams) | |||
| console.log(subtitleParamsToObj); | |||
| SubtitlesFontFamily.value=subtitleParamsToObj.Fontname | |||
| SubtitlesSize.value=subtitleParamsToObj.Fontsize | |||
| SubtitlesWidth.value=subtitleParamsToObj.Boxwidth | |||
| SubtitlesSize.value=Number(subtitleParamsToObj.Boxheight-10) | |||
| // Boxheight:SubtitlesBox.value.style.height, | |||
| SubtitlesLeft.value=subtitleParamsToObj.Marginl | |||
| SubtitlesTop.value=subtitleParamsToObj.Marginy | |||
| SubtitlesColor.value=BgraToRgba(subtitleParamsToObj.SecondaryColour | |||
| ) | |||
| SubtitlesBgc.value=BgraToRgba(subtitleParamsToObj.OutlineColour | |||
| ) | |||
| } | |||
| //#endregion ---------------------------- | |||
| @@ -2028,28 +2087,28 @@ const canvasImgBox = ref(null); // 图片外盒子dom | |||
| const SubtitlesAngle = ref(20); //旋转度数 | |||
| const lastMouseAngle = ref(0); | |||
| const initialRotation = ref(0); | |||
| const SubtitlesColor = ref('rgba(255, 255, 255, 1)'); // 字幕字色 | |||
| const SubtitlesColorBGRA = ref(rgbaToBgra(SubtitlesColor.value)); // 字幕字色 | |||
| const SubtitlesBgc = ref('rgba(0, 0, 0, 1)'); // 字幕背景色 | |||
| const SubtitlesBgcBGRA = ref(rgbaToBgra(SubtitlesBgc.value)); // 字幕背景色 | |||
| const SubtitlesColor = ref('#ff0000'); // 字幕字色 | |||
| // const SubtitlesColorBGRA = ref(rgbaToBgra(SubtitlesColor.value)); // 字幕字色 | |||
| const SubtitlesBgc = ref('#ffffff'); // 字幕背景色 | |||
| // const SubtitlesBgcBGRA = ref(rgbaToBgra(SubtitlesBgc.value)); // 字幕背景色 | |||
| // 调色板 | |||
| const colorList = [ | |||
| 'rgba(255, 0, 0, 1)', // 红色 | |||
| 'rgba(0, 255, 0, 1)', // 绿色 | |||
| 'rgba(0, 0, 255, 1)', // 蓝色 | |||
| 'rgba(255, 255, 0, 1)', // 黄色 | |||
| 'rgba(0, 0, 0, 1)', // 黑色 | |||
| 'rgba(0, 255, 255, 1)', // 青色 | |||
| 'rgba(128, 0, 0, 1)', // 深红色 | |||
| 'rgba(0, 128, 0, 1)', // 深绿色 | |||
| 'rgba(0, 0, 128, 1)', // 深蓝色 | |||
| 'rgba(255, 255, 255, 1)', // 白色 | |||
| 'rgba(128, 0, 128, 1)', // 深品红色 | |||
| 'rgba(0, 128, 128, 1)', // 深青色 | |||
| 'rgba(255, 128, 0, 1)', // 橙色 | |||
| 'rgba(255, 0, 128, 1)', // 粉红色 | |||
| 'rgba(0, 255, 128, 1)', // 中绿色 | |||
| 'rgba(128, 255, 0, 1)' // 中黄色 | |||
| const colorList = [ | |||
| '#ff0000', // 红色 | |||
| '#00ff00', // 绿色 | |||
| '#0000ff', // 蓝色 | |||
| '#ffff00', // 黄色 | |||
| '#000000', // 黑色 | |||
| '#00ffff', // 青色 | |||
| '#800000', // 深红色 | |||
| '#008000', // 深绿色 | |||
| '#000080', // 深蓝色 | |||
| '#ffffff', // 白色 | |||
| '#800080', // 深品红色 | |||
| '#008080', // 深青色 | |||
| '#ff8000', // 橙色 | |||
| '#ff0080', // 粉红色 | |||
| '#00ff80', // 中绿色 | |||
| '#80ff00' // 中黄色 | |||
| ]; | |||
| const fontFamilyList = [ | |||
| {label:"黑体",value:"SimHei"}, | |||
| @@ -2081,40 +2140,43 @@ const handleClickOutside = () => { | |||
| onMounted(() => { | |||
| document.addEventListener('click',handleClickOutside); | |||
| }); | |||
| function rgbaToBgra(rgba) { | |||
| const regex = /rgba\((\d+),\s*(\d+),\s*(\d+),\s*(\d+(\.\d+)?)\)/; | |||
| const match = regex.exec(rgba); | |||
| if (match) { | |||
| const red = parseInt(match[1]); | |||
| const green = parseInt(match[2]); | |||
| const blue = parseInt(match[3]); | |||
| const alpha = parseFloat(match[4]); | |||
| const b = blue; | |||
| const g = green; | |||
| const r = red; | |||
| const a = Math.round(alpha * 255); | |||
| const bgra = `bgra(${b}, ${g}, ${r}, ${a})`; | |||
| return bgra; | |||
| } | |||
| // Return the original value if no match is found | |||
| return rgba; | |||
| function rgbaToBgra(hexColor) { | |||
| // 去除颜色前缀 | |||
| hexColor = hexColor.replace("#", ""); | |||
| // 分割颜色分量 | |||
| const red = hexColor.substring(0, 2); | |||
| const green = hexColor.substring(2, 4); | |||
| const blue = hexColor.substring(4, 6); | |||
| // 组合为新的颜色字符串 | |||
| const convertedColor = `&H${red}${green}${blue}`; | |||
| return convertedColor; | |||
| } | |||
| watch( | |||
| () => SubtitlesColor, | |||
| (newValue, oldValue) => { | |||
| SubtitlesColorBGRA.value = ref(rgbaToBgra(SubtitlesColor.value)); // 字幕字色 | |||
| }, | |||
| { deep: true } | |||
| ); | |||
| watch( | |||
| () => SubtitlesBgc, | |||
| (newValue, oldValue) => { | |||
| SubtitlesBgcBGRA.value = ref(rgbaToBgra(SubtitlesBgc.value)); // 字幕背景色 | |||
| }, | |||
| { deep: true } | |||
| ); | |||
| function BgraToRgba(hexColor) { | |||
| // 去除颜色前缀 | |||
| hexColor = hexColor.replace("&H", ""); | |||
| // 分割颜色分量 | |||
| const red = hexColor.substring(0, 2); | |||
| const green = hexColor.substring(2, 4); | |||
| const blue = hexColor.substring(4, 6); | |||
| // 组合为新的颜色字符串 | |||
| const convertedColor = `#${red}${green}${blue}`; | |||
| return convertedColor; | |||
| } | |||
| // watch( | |||
| // () => SubtitlesColor, | |||
| // (newValue, oldValue) => { | |||
| // SubtitlesColorBGRA.value = ref(rgbaToBgra(SubtitlesColor.value)); // 字幕字色 | |||
| // }, | |||
| // { deep: true } | |||
| // ); | |||
| // watch( | |||
| // () => SubtitlesBgc, | |||
| // (newValue, oldValue) => { | |||
| // SubtitlesBgcBGRA.value = ref(rgbaToBgra(SubtitlesBgc.value)); // 字幕背景色 | |||
| // }, | |||
| // { deep: true } | |||
| // ); | |||
| // 计算属性来计算盒子位置 | |||
| const SubtitlesStyle = computed(() => { | |||
| return { | |||
| @@ -2125,7 +2187,6 @@ watch( | |||
| fontFamily: SubtitlesFontFamily.value, | |||
| color: SubtitlesColor.value, | |||
| backgroundColor: SubtitlesBgc.value, | |||
| }; | |||
| }); | |||
| @@ -2421,7 +2482,7 @@ onUnmounted(() => { | |||
| } | |||
| } | |||
| .el-input { | |||
| width: 60px; | |||
| width: 50px; | |||
| height: 25px; | |||
| } | |||
| .el-input__wrapper { | |||
| @@ -114,6 +114,11 @@ | |||
| <div style="margin-bottom: 5px" @click="loginFlag(2)"> | |||
| <span class="join">{{ $t("login.signUp") }}</span> | |||
| </div> | |||
| <div style="margin-bottom: 5px"> | |||
| <span class="join" @click="loginFlag(8)">{{ | |||
| $t("login.loginByPhone") | |||
| }}</span> | |||
| </div> | |||
| <div> | |||
| <span class="join" @click="loginFlag(3)">{{ | |||
| $t("login.forgetPwd") | |||
| @@ -553,6 +558,12 @@ | |||
| :placeholder="$t('login.SMSCode')" | |||
| name="email" | |||
| /> | |||
| <span class="captcha"> | |||
| <div v-if="SMSTimeOut == 0" @click="" class="sendSMSBtn"> | |||
| {{ $t("login.sendSMS") }} | |||
| </div> | |||
| <div v-if="SMSTimeOut != 0" class="sendSMSBtn">{{ SMSTimeOut }}s</div> | |||
| </span> | |||
| </el-form-item> | |||
| <el-button | |||
| @@ -587,6 +598,213 @@ | |||
| </div> | |||
| </div> | |||
| </el-form> | |||
| <!-- 忘记密码手机号 --> | |||
| <el-form | |||
| v-if="isLogin == 7" | |||
| ref="loginFormRef" | |||
| :model="loginData7" | |||
| :rules="loginRules" | |||
| class="login-form" | |||
| > | |||
| <div class="flex text-white items-center"> | |||
| <span class="flex-1 text-center">{{ | |||
| $t("login.title") + " " + $t("login.resetPassword") | |||
| }}</span> | |||
| <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="SMScode"> | |||
| <span class="text-white"> | |||
| <svg-icon icon-class="password" /> | |||
| </span> | |||
| <el-input | |||
| class="flex-1" | |||
| v-model="loginData7.SMScode" | |||
| :placeholder="$t('login.SMSCode')" | |||
| type="input" | |||
| size="large" | |||
| name="password" | |||
| /> | |||
| <span class="captcha"> | |||
| <div v-if="SMSTimeOut == 0" @click="" class="sendSMSBtn"> | |||
| {{ $t("login.sendSMS") }} | |||
| </div> | |||
| <div v-if="SMSTimeOut != 0" class="sendSMSBtn">{{ SMSTimeOut }}s</div> | |||
| </span> | |||
| </el-form-item> | |||
| <el-form-item prop="password"> | |||
| <span class="text-white"> | |||
| <svg-icon icon-class="password" /> | |||
| </span> | |||
| <el-input | |||
| class="flex-1" | |||
| v-model="loginData7.password" | |||
| :placeholder="$t('login.newPwd')" | |||
| :type="passwordVisible === false ? 'password' : 'input'" | |||
| size="large" | |||
| name="password" | |||
| /> | |||
| <span class="mr-2" @click="passwordVisible = !passwordVisible"> | |||
| <svg-icon | |||
| :icon-class="passwordVisible === false ? 'eye' : 'eye-open'" | |||
| class="text-white cursor-pointer" | |||
| /> | |||
| </span> | |||
| </el-form-item> | |||
| <el-form-item prop="confirmPassword4"> | |||
| <span class="text-white"> | |||
| <svg-icon icon-class="password" /> | |||
| </span> | |||
| <el-input | |||
| class="flex-1" | |||
| v-model="loginData7.confirmPassword4" | |||
| :placeholder="$t('login.confirmNewPwd')" | |||
| :type="passwordVisible === false ? 'password' : 'input'" | |||
| size="large" | |||
| name="confirmPassword4" | |||
| /> | |||
| <span class="mr-2" @click="passwordVisible = !passwordVisible"> | |||
| <svg-icon | |||
| :icon-class="passwordVisible === false ? 'eye' : 'eye-open'" | |||
| class="text-white cursor-pointer" | |||
| /> | |||
| </span> | |||
| </el-form-item> | |||
| <el-button | |||
| size="default" | |||
| :loading="loading" | |||
| type="primary" | |||
| class="loginBtn" | |||
| @click.prevent="resetPwdForm" | |||
| > | |||
| <el-icon | |||
| v-if="isRegistering" | |||
| style="margin-right: 10px" | |||
| 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> | |||
| {{ $t("login.confirm") }} | |||
| </el-button> | |||
| <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'"> | |||
| <div style="margin-bottom: 5px" @click="loginFlag(1)"> | |||
| <span class="join">{{ $t("login.signIn") }}</span> | |||
| </div> | |||
| <div> | |||
| <span | |||
| class="join" | |||
| @click="router.push({ path: 'createVideo', params: {} })" | |||
| >{{ $t("login.gohome") }}</span | |||
| > | |||
| </div> | |||
| </div> | |||
| </el-form> | |||
| <!-- 手机号登录 --> | |||
| <el-form | |||
| v-if="isLogin == 8" | |||
| ref="loginFormRef" | |||
| :model="loginData8" | |||
| :rules="loginRules" | |||
| class="login-form" | |||
| > | |||
| <div class="flex text-white items-center"> | |||
| <span class="flex-1 text-center">{{ | |||
| $t("login.title") + " " + $t("login.register") | |||
| }}</span> | |||
| <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="phone"> | |||
| <div class="text-white"> | |||
| <svg-icon icon-class="user" /> | |||
| </div> | |||
| <el-input | |||
| class="flex-1" | |||
| ref="email" | |||
| size="large" | |||
| v-model="loginData8.phone" | |||
| :placeholder="$t('login.phone')" | |||
| name="email" | |||
| /> | |||
| </el-form-item> | |||
| <el-form-item prop="SMSCode"> | |||
| <div class="text-white"> | |||
| <svg-icon icon-class="user" /> | |||
| </div> | |||
| <el-input | |||
| class="flex-1" | |||
| ref="email" | |||
| size="large" | |||
| v-model="loginData8.SMScode" | |||
| :placeholder="$t('login.SMSCode')" | |||
| name="email" | |||
| /> | |||
| <span class="captcha"> | |||
| <div v-if="SMSTimeOut == 0" @click="" class="sendSMSBtn"> | |||
| {{ $t("login.sendSMS") }} | |||
| </div> | |||
| <div v-if="SMSTimeOut != 0" class="sendSMSBtn">{{ SMSTimeOut }}s</div> | |||
| </span> | |||
| </el-form-item> | |||
| <el-button | |||
| size="default" | |||
| :loading="loading" | |||
| type="primary" | |||
| class="loginBtn" | |||
| @click.prevent="handleRegister" | |||
| > | |||
| <el-icon | |||
| v-if="isRegistering" | |||
| style="margin-right: 10px" | |||
| 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> | |||
| {{ $t("login.registerBtn") }} | |||
| </el-button> | |||
| <div :class="currentLan == 'zh-cn' ? 'bottomBtnCN' : 'bottomBtnEN'"> | |||
| <div style="margin-bottom: 5px" @click="loginFlag(1)"> | |||
| <span class="join">{{ $t("login.loginByEmail") }}</span> | |||
| </div> | |||
| </div> | |||
| </el-form> | |||
| </div> | |||
| </template> | |||
| @@ -676,6 +894,15 @@ const loginData5 = ref({ | |||
| const loginData6 = ref({ | |||
| SMSCode: "", | |||
| }); | |||
| const loginData7 = ref({ | |||
| SMScode: "", | |||
| password: "", | |||
| confirmPassword4: "", | |||
| }); | |||
| const loginData8 = ref({ | |||
| phone: "", | |||
| SMScode: "", | |||
| }); | |||
| const loginRules = ref({ | |||
| email: [ | |||
| @@ -935,33 +1162,48 @@ function handleRegister() { | |||
| //#region 忘记密码 表单3 | |||
| function sendEmailforgetPwd() { | |||
| const msg = | |||
| currentLan.value == "zh-cn" | |||
| ? "确认信息已发送至您的邮箱,请注意查收" | |||
| : "An email has been send to you, Please pay attention to confirm"; | |||
| loginFormRef.value.validate(async (val: any) => { | |||
| if (val) { | |||
| const data = { | |||
| email: loginData3.value.email, | |||
| }; | |||
| await sendUpdPwdEmailApi(data.email) | |||
| .then((res) => { | |||
| console.log(res, "res"); | |||
| ElMessage.success(msg); | |||
| }) | |||
| .catch((err) => { | |||
| console.log(err, "err"); | |||
| ElMessage.error(err.message); | |||
| }); | |||
| } else { | |||
| const msg = | |||
| currentLan.value == "zh-cn" | |||
| ? "请检查信息格式!" | |||
| : "Please check the format !"; | |||
| ElMessage.error(msg); | |||
| return; | |||
| } | |||
| }); | |||
| const emailReg = | |||
| /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; | |||
| const phoneReg = /^[1][3-9]\d{9}$/; | |||
| if (phoneReg.test(loginData3.value.email)) { | |||
| isLogin.value = 7; | |||
| return; | |||
| } else if (emailReg.test(loginData3.value.email)) { | |||
| const msg = | |||
| currentLan.value == "zh-cn" | |||
| ? "确认信息已发送至您的邮箱,请注意查收" | |||
| : "An email has been send to you, Please pay attention to confirm"; | |||
| loginFormRef.value.validate(async (val: any) => { | |||
| if (val) { | |||
| const data = { | |||
| email: loginData3.value.email, | |||
| }; | |||
| await sendUpdPwdEmailApi(data.email) | |||
| .then((res) => { | |||
| console.log(res, "res"); | |||
| ElMessage.success(msg); | |||
| }) | |||
| .catch((err) => { | |||
| console.log(err, "err"); | |||
| ElMessage.error(err.message); | |||
| }); | |||
| } else { | |||
| const msg = | |||
| currentLan.value == "zh-cn" | |||
| ? "请检查信息格式!" | |||
| : "Please check the format !"; | |||
| ElMessage.error(msg); | |||
| return; | |||
| } | |||
| }); | |||
| } else { | |||
| const msg = | |||
| currentLan.value == "zh-cn" | |||
| ? "请检查信息格式!" | |||
| : "Please check the format !"; | |||
| ElMessage.error(msg); | |||
| return; | |||
| } | |||
| } | |||
| //#endregion -------------------------- | |||
| @@ -1061,7 +1303,7 @@ async function doRegister(data: object) { | |||
| ElMessage.error(err.message); | |||
| }); | |||
| } | |||
| // 发送手机验证码 | |||
| // 注册时发送手机验证码后 | |||
| const SMSTimeOut = ref(0); //倒计时 | |||
| async function doRegisterByPhone(data: object) { | |||
| const msg = | |||
| @@ -1214,6 +1456,15 @@ onMounted(() => { | |||
| height: 48px; | |||
| cursor: pointer; | |||
| } | |||
| .sendSMSBtn { | |||
| width: 120px; | |||
| height: 48px; | |||
| line-height: 48px; | |||
| color: #fff; | |||
| text-align: center; | |||
| background: linear-gradient(270deg, #4b61dc, #15d1b8); | |||
| cursor: pointer; | |||
| } | |||
| } | |||
| &:hover { | |||
| backdrop-filter: blur(7px); | |||
| @@ -662,6 +662,7 @@ onMounted(() => { | |||
| padding-left: 5px; | |||
| margin-top: -5px; | |||
| line-height: 20px; | |||
| font-size: 13px; | |||
| cursor: pointer; | |||
| } | |||
| &:hover { | |||