@@ -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 { | |||