congzc 1 yıl önce
ebeveyn
işleme
dbfd8ded0e
12 değiştirilmiş dosya ile 732 ekleme ve 189 silme
  1. +97
    -0
      src/apis/login copy.js
  2. +34
    -7
      src/apis/login.js
  3. +1
    -1
      src/components/LangSelect/index.vue
  4. +4
    -3
      src/lang/package/en.ts
  5. +4
    -3
      src/lang/package/zh-cn.ts
  6. +174
    -72
      src/layout/index.vue
  7. +1
    -0
      src/styles/my.scss
  8. +2
    -0
      src/types/auto-imports.d.ts
  9. +1
    -0
      src/types/components.d.ts
  10. +159
    -45
      src/views/createVideo/index.vue
  11. +213
    -58
      src/views/login/index.vue
  12. +42
    -0
      src/views/moveImg/index.vue

+ 97
- 0
src/apis/login copy.js Dosyayı Görüntüle

@@ -0,0 +1,97 @@
import request from "@/utils/request.js";

const baseURL = import.meta.env.VITE_APP_BASE_API

/**
* @description 注册
* @params email,password
* @returns data
*/
export function register(data) {
return request({
url: `/api/user/doRegisterByEmail`,
method: 'post',
data
})
}

/**
* @description 登录
* @params email,password,code
* @returns data
*/
export function login(data) {
return request({
url: `/api/user/loginByEmail`,
method: 'post',
data
})
}

/**
/**
* @description:重新发送邮件
* @param {string} data
* @return: data
*/
export function sendRegisterEmail(email) {
return request({
url: `/api/user/sendRegisterEmail`,
method: 'post',
data: {
email
}
})
}

/**
/**
* @description:忘记密码发送邮件
* @param {string} data
* @return: data
*/
export function sendUpdPwdEmailApi(email) {
return request({
url: `/api/user/sendUpdPwdEmail`,
method: 'post',
data: {
email
}
})
}

/**
/**
* @description:邮件重置密码,
* @param pwd, ticket
* @return: data
*/
export function resetPwdEmailApi(data) {
return request({
url: `/api/user/doUpdPass`,
method: 'post',
data
})
}

/**
/**
* @description:邮件重置密码,
* @param oldpwd, newpwd
* @return: data
*/
export function resetPwdFormApi(data) {
return request({
url: `/api/user/oldUpdPass`,
method: 'post',
data
})
}


/**
* @description:获取图形验证码
* @return: 验证码地址
*/
export const getCodeImgUrl = baseURL + '/api/user/captcha.jpg'


+ 34
- 7
src/apis/login.js Dosyayı Görüntüle

@@ -9,7 +9,8 @@ const baseURL = import.meta.env.VITE_APP_BASE_API
*/ */
export function register(data) { export function register(data) {
return request({ return request({
url: `/api/user/doRegisterByEmail`,
// url: `/api/user/doRegisterByEmail`,
url: `/api/user/doRegisterByPhone`,
method: 'post', method: 'post',
data data
}) })
@@ -22,7 +23,8 @@ export function register(data) {
*/ */
export function login(data) { export function login(data) {
return request({ return request({
url: `/api/user/loginByEmail`,
// url: `/api/user/loginByEmail`,
url: `/api/user/login`,
method: 'post', method: 'post',
data data
}) })
@@ -50,16 +52,41 @@ export function sendRegisterEmail(email) {
* @param {string} data * @param {string} data
* @return: data * @return: data
*/ */
export function sendUpdPwdEmailApi(email) {
// export function sendUpdPwdEmailApi(email) {
// return request({
// url: `/api/user/sendUpdPwdEmail`,
// method: 'post',
// data: {
// email
// }
// })
// }
/**`/api/user/sendLoginPhoneCode?phone=${phone}`
* @description 忘记密码第一步,根据图片验证码和手机号获取短信
* @param {object} loginParams (phone,code)
* @returns data
*/
export function sendUpdPwdEmailApi(data) {
return request({
url: `/api/user/sendPhoneCode?phone=${data.phone}&code=${data.code}`,
method: 'get',
})
}

/**`/api/user/sendLoginPhoneCode?phone=${phone}`
* @description 忘记密码第二步,短信验证码和新密码
* @param {object} loginParams (phone,code,pwd)
* @returns data
*/
export function doUpdPassApi(loginParams) {
return request({ return request({
url: `/api/user/sendUpdPwdEmail`,
url: `/api/user/updPass`,
method: 'post', method: 'post',
data: {
email
}
data: loginParams
}) })
} }



/** /**
/** /**
* @description:邮件重置密码, * @description:邮件重置密码,


+ 1
- 1
src/components/LangSelect/index.vue Dosyayı Görüntüle

@@ -1,7 +1,7 @@
<template> <template>
<el-dropdown class="outSide" trigger="click" @command="handleLanguageChange"> <el-dropdown class="outSide" trigger="click" @command="handleLanguageChange">
<div> <div>
<svg-icon icon-class="language" />
<svg-icon icon-class="language" style="color: #fff" />
</div> </div>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>


+ 4
- 3
src/lang/package/en.ts Dosyayı Görüntüle

@@ -15,7 +15,7 @@ export default {
login: { login: {
title: "Metavatar-PC", title: "Metavatar-PC",
username: "Username", username: "Username",
email: "E-mail",
email: "Phone",
password: "Password", password: "Password",
confirmPassword: "Confirm password", confirmPassword: "Confirm password",
login: "Sign in", login: "Sign in",
@@ -27,14 +27,15 @@ export default {
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 SMS Code',
resetPassword:'Reset password', resetPassword:'Reset password',
setNewPwd:'Set new password', setNewPwd:'Set new password',
newPwd:'New password', newPwd:'New password',
oldPwd:'Old password', oldPwd:'Old password',
confirmNewPwd:'Confirm new password', confirmNewPwd:'Confirm new password',
confirm:'Confirm', confirm:'Confirm',
gohome:'Back to home page'
gohome:'Back to home page',
SMSCode:'SMS Code'
}, },


// 导航栏国际化 // 导航栏国际化


+ 4
- 3
src/lang/package/zh-cn.ts Dosyayı Görüntüle

@@ -15,7 +15,7 @@ export default {
login: { login: {
title: "Metavatar-PC", title: "Metavatar-PC",
username: "用户名", username: "用户名",
email: "电子邮件",
email: "手机号",
password: "密码", password: "密码",
confirmPassword: "确认密码", confirmPassword: "确认密码",
login: "登录", login: "登录",
@@ -27,14 +27,15 @@ export default {
signUp: "没有账号?现在加入!", signUp: "没有账号?现在加入!",
forgetPwd: "忘记密码", forgetPwd: "忘记密码",
forgetPwdTitle:'忘记密码', forgetPwdTitle:'忘记密码',
SendEmail:'发送邮件',
SendEmail:'发送短信验证码',
resetPassword:'重置密码', resetPassword:'重置密码',
setNewPwd:'设置新密码', setNewPwd:'设置新密码',
newPwd:'新密码', newPwd:'新密码',
oldPwd:'旧密码', oldPwd:'旧密码',
confirmNewPwd:'确认新密码', confirmNewPwd:'确认新密码',
confirm:'确定', confirm:'确定',
gohome:'回到首页'
gohome:'回到首页',
SMSCode:'短信验证码',
}, },


// 导航栏国际化 // 导航栏国际化


+ 174
- 72
src/layout/index.vue Dosyayı Görüntüle

@@ -1,25 +1,52 @@
<template> <template>
<div :class="classObj" class="app-wrapper">
<!-- 手机设备侧边栏打开遮罩层 -->
<div
v-if="classObj.mobile && classObj.openSidebar"
class="drawer-bg"
@click="handleOutsideClick"
></div>

<Sidebar class="sidebar-container" />

<div :class="{ hasTagsView: showTagsView }" class="main-container">
<div
:class="{ 'fixed-header': fixedHeader }"
style="box-shadow: rgba(0, 0, 0, 0.05) 0px 4px 4px; height: 80px"
>
<navbar />
<tags-view v-if="showTagsView" />
<div class="app-wrapper">
<!-- 侧边栏 -->
<div class="Sidebar">
<div class="imgBox">
<img
class="boxCentreImg"
src="../assets//img/left-top-logo.png"
alt=""
/>
</div>
<!-- 侧边路由列表 -->
<div class="myRouter">
<div class="myRouter-item" @click="router.push('/createVideo')">
<div class="icon">
<el-icon><i-ep-edit /></el-icon>
</div>
{{ $t("createVideo.title") }}
</div>
<div class="myRouter-item" @click="router.push('/moveImg')">
<div class="icon">
<el-icon><i-ep-edit /></el-icon>
</div>
{{ $t("createVideo.title") }}
</div>
</div>
</div>
<!-- 右边显示部分 -->
<div class="rightBox">
<!-- nav栏 -->
<div class="nav">
<!-- 语言 -->
<lang-select class="navItem" />
<!-- 登录 -->
<div class="navItem" v-if="!AccessToken" @click="router.push('login')">
{{ $t("navbar.goLogin") }}
</div>
<!-- 注销 -->
<div
class="navItem"
v-if="AccessToken"
@click="logout"
style="margin-left: 10px"
>
{{ $t("navbar.logout") }}
</div>
</div> </div>

<!-- 主页面 --> <!-- 主页面 -->
<app-main />
<app-main style="background-color: #000" />
</div> </div>
</div> </div>
</template> </template>
@@ -28,16 +55,41 @@
import { computed, watchEffect } from "vue"; import { computed, watchEffect } from "vue";
import { useWindowSize } from "@vueuse/core"; import { useWindowSize } from "@vueuse/core";
import { AppMain, Navbar } from "./components/index"; import { AppMain, Navbar } from "./components/index";
import SignSucceed from "../views/signSucceed/index.vue";
import Sidebar from "./components/Sidebar/index.vue";


import LangSelect from "@/components/LangSelect/index.vue";
import { useAppStore } from "@/store/modules/app"; import { useAppStore } from "@/store/modules/app";
import { useSettingsStore } from "@/store/modules/settings";
// import { useSettingsStore } from "@/store/modules/settings";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { useI18n } from "vue-i18n";

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

const userInfoPinia = userInfoModules();
const route = useRoute(); const route = useRoute();
const router = useRouter();
const { params } = route; const { params } = route;
const { width } = useWindowSize(); const { width } = useWindowSize();

const AccessToken = localStorage.getItem("AccessToken");
// 当前语言状态与国际化组件
const { locale } = useI18n();
const lanChange = ref(locale);
function logout() {
const msg =
(lanChange.value as string) == "zh-cn"
? "确定退出登录吗?"
: "Are you sure to log out?";
const notice = (lanChange.value as string) == "zh-cn" ? "提示" : "Notice";
const confirm = (lanChange.value as string) == "zh-cn" ? "确定" : "Confirm";
const cancel = (lanChange.value as string) == "zh-cn" ? "取消" : "Cancel";
ElMessageBox.confirm(msg, notice, {
confirmButtonText: confirm,
cancelButtonText: cancel,
}).then(() => {
userInfoPinia.loginOut();
router.push(`/login`);
localStorage.removeItem("AccessToken");
});
}
/** /**
* 响应式布局容器固定宽度 * 响应式布局容器固定宽度
* *
@@ -48,18 +100,7 @@ const { width } = useWindowSize();
const WIDTH = 992; const WIDTH = 992;


const appStore = useAppStore(); const appStore = useAppStore();
const settingsStore = useSettingsStore();

const fixedHeader = computed(() => settingsStore.fixedHeader);
const showTagsView = computed(() => settingsStore.tagsView);
const showSettings = computed(() => settingsStore.showSettings);

const classObj = computed(() => ({
hideSidebar: !appStore.sidebar.opened,
openSidebar: appStore.sidebar.opened,
withoutAnimation: appStore.sidebar.withoutAnimation,
mobile: appStore.device === "mobile",
}));
// const settingsStore = useSettingsStore();


watchEffect(() => { watchEffect(() => {
if (width.value < WIDTH) { if (width.value < WIDTH) {
@@ -84,48 +125,109 @@ function handleOutsideClick() {
onMounted(() => {}); onMounted(() => {});
</script> </script>


<!-- 新样式 -->
<style lang="scss" scoped> <style lang="scss" scoped>
.app-wrapper { .app-wrapper {
&::after {
display: table;
clear: both;
content: "";
width: 1920px;
display: flex;
}
.Sidebar {
width: 230px;
background-color: #000;
height: 100vh;
color: #fff;
.imgBox {
width: 100%;
height: 80px;
position: relative;
img {
max-width: 80%;
max-height: 80%;
}
} }
.myRouter {
position: relative;
height: calc(100% - 80px);
padding: 200px 20px 0;
color: #fff;
// color: #868593;

&-item {
display: flex;
width: 100%;
height: 50px;
padding-left: 10px;
font-size: 20px;
font-weight: 500;
line-height: 50px;
text-align: center;
cursor: pointer;
// border-bottom: 2px solid #fff;
transition: all 0.3s;
border-radius: 5px;
margin-bottom: 20px;
margin-right: 20px;

.icon {
width: 40px;
height: 40px;
color: #fff;
border-radius: 50%;

.el-icon {
width: 25px;
height: 25px;
font-size: 25px;
// color: #797a9f;
color: #fff;
text-align: center;
vertical-align: sub;
}
}

&:hover {
// background: rgba(255, 255, 255, 0.2);
color: #000;
background: #fff;
.el-icon {
// color: #d4d0ff;
color: #000;
}
}
}


position: relative;
width: 100%;
height: 100%;
e &.mobile.openSidebar {
position: fixed;
top: 0;
.pricing {
position: absolute;
bottom: 60px;
width: calc(100% - 40px);
text-align: center;
}
.API {
position: absolute;
bottom: 0px;
width: calc(100% - 40px);
text-align: center;
}
} }
} }

.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - #{$sideBarWidth});
transition: width 0.28s;
}

.hideSidebar .fixed-header {
width: calc(100% - 54px);
}

.mobile .fixed-header {
width: 100%;
}

.drawer-bg {
position: absolute;
top: 0;
z-index: 999;
width: 100%;
height: 100%;
// background: #1b213a;
background: #000;
opacity: 0.3;
.rightBox {
width: 1690px;
// background-color: #000;
.nav {
display: flex;
justify-content: flex-end;
align-items: center;
margin-right: 20px;
width: 100%;
height: 80px;
background-color: #000;
padding: 30px;
// padding: 30px 30px 0 1500px;
color: #fff;
.navItem {
font-size: 16px;
margin-right: 30px;
}
}
} }
</style> </style>

+ 1
- 0
src/styles/my.scss Dosyayı Görüntüle

@@ -1,5 +1,6 @@
body { body {
font-family: Arial, Microsoft YaHei, 黑体, 宋体, sans-serif; font-family: Arial, Microsoft YaHei, 黑体, 宋体, sans-serif;
font-size: 14px;
} }


.inmiddle { .inmiddle {


+ 2
- 0
src/types/auto-imports.d.ts Dosyayı Görüntüle

@@ -2,6 +2,7 @@
export {} export {}
declare global { declare global {
const EffectScope: typeof import('vue')['EffectScope'] const EffectScope: typeof import('vue')['EffectScope']
const ElForm: typeof import('element-plus/es')['ElForm']
const ElMessage: typeof import('element-plus/es')['ElMessage'] const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox'] const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
@@ -270,6 +271,7 @@ import { UnwrapRef } from 'vue'
declare module 'vue' { declare module 'vue' {
interface ComponentCustomProperties { interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']> readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly ElForm: UnwrapRef<typeof import('element-plus/es')['ElForm']>
readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']> readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']> readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']>
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']> readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>


+ 1
- 0
src/types/components.d.ts Dosyayı Görüntüle

@@ -24,6 +24,7 @@ declare module '@vue/runtime-core' {
ElSelect: typeof import('element-plus/es')['ElSelect'] ElSelect: typeof import('element-plus/es')['ElSelect']
ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs'] ElTabs: typeof import('element-plus/es')['ElTabs']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
GithubCorner: typeof import('./../components/GithubCorner/index.vue')['default'] GithubCorner: typeof import('./../components/GithubCorner/index.vue')['default']
Hamburger: typeof import('./../components/Hamburger/index.vue')['default'] Hamburger: typeof import('./../components/Hamburger/index.vue')['default']
IconSelect: typeof import('./../components/IconSelect/index.vue')['default'] IconSelect: typeof import('./../components/IconSelect/index.vue')['default']


+ 159
- 45
src/views/createVideo/index.vue Dosyayı Görüntüle

@@ -6,8 +6,23 @@
<div class="left"> <div class="left">
<!-- 选择模版弹出框 --> <!-- 选择模版弹出框 -->
<div class="chooseModelBox" :class="showChooseModel ? '' : 'noModel'"> <div class="chooseModelBox" :class="showChooseModel ? '' : 'noModel'">
<!-- 箭头 -->
<!-- 伸缩按钮 -->
<div <div
v-if="showChooseModel && videoType"
class="shrinkBtn"
@click="showChooseModel = false"
>
&gt;
</div>
<div
v-if="!showChooseModel"
class="shrinkBtn"
@click="showChooseModel = true"
>
&lt;
</div>
<!-- 箭头 -->
<!-- <div
v-if="showChooseModel && videoType" v-if="showChooseModel && videoType"
class="openChooseModel" class="openChooseModel"
@click="showChooseModel = false" @click="showChooseModel = false"
@@ -20,8 +35,9 @@
@click="showChooseModel = true" @click="showChooseModel = true"
> >
<img src="../../assets/img/arrowRight.png" alt="" /> <img src="../../assets/img/arrowRight.png" alt="" />
</div>
</div> -->
<!-- tab栏 --> <!-- tab栏 -->
<p>性别</p>
<div class="tab" v-show="showChooseModel"> <div class="tab" v-show="showChooseModel">
<div <div
class="tabItem" class="tabItem"
@@ -45,6 +61,30 @@
女性 女性
</div> </div>
</div> </div>
<p>视频比例</p>
<div class="tab" v-show="showChooseModel">
<div
class="tabItem"
:class="modelTabItemActive2 == 0 ? 'tabItemActive' : ''"
@click="changeTabVideoType(0)"
>
全部
</div>
<div
class="tabItem"
:class="modelTabItemActive2 == 2 ? 'tabItemActive' : ''"
@click="changeTabVideoType(2)"
>
横屏
</div>
<div
class="tabItem"
:class="modelTabItemActive2 == 1 ? 'tabItemActive' : ''"
@click="changeTabVideoType(1)"
>
竖屏
</div>
</div>
<!-- 模版列表 --> <!-- 模版列表 -->
<div <div
class="modeListBox" class="modeListBox"
@@ -296,19 +336,32 @@ const lanChange = ref(locale);
const AccessToken = localStorage.getItem("AccessToken"); // 判断有没有登录 const AccessToken = localStorage.getItem("AccessToken"); // 判断有没有登录


//#region 选择模版弹出框 //#region 选择模版弹出框
const videoType = ref(null); //判断横屏2还是竖屏1
const videoType = ref(null); //判断横屏2还是竖屏1,初始为没有,控制按钮显隐
const showChooseModel = ref(true); // 控制弹窗显示隐藏 const showChooseModel = ref(true); // 控制弹窗显示隐藏
const modeList = ref([]); //模版列表 const modeList = ref([]); //模版列表
const modelImg = ref(null); //模版回显图 const modelImg = ref(null); //模版回显图
const modelTabItemActive = ref(0); //模版tab栏
const modelTabItemActive = ref(0); //模版tab栏 性别
const modelTabItemActive2 = ref(0); //模版tab栏 比例
const modelPageNum = ref(1); const modelPageNum = ref(1);
const modelPageSize = ref(20); const modelPageSize = ref(20);
const overLoadModel = ref(true); //禁用模版加载更多 const overLoadModel = ref(true); //禁用模版加载更多
const modelId = ref(null); // 选中模版的id const modelId = ref(null); // 选中模版的id
// 获取模版列表 // 获取模版列表
async function getModeList(sex, pageNum, pageSize) { async function getModeList(sex, pageNum, pageSize) {
const res = await modeListApi(sex, pageNum, pageSize);
modeList.value = res.data.list;
let sexx = null;
if (sex == 0) {
sexx = "";
} else {
sexx = sex;
}
const res = await modeListApi(sexx, pageNum, pageSize);
if (tabVideoType.value == 0) {
modeList.value = res.data.list;
} else {
modeList.value = res.data.list.filter(
(item) => item.videoType == tabVideoType.value
);
}
overLoadModel.value = false; overLoadModel.value = false;
} }
// 点击模版 // 点击模版
@@ -318,18 +371,45 @@ function clickModelItem(item) {
videoType.value = item.videoType; videoType.value = item.videoType;
modelId.value = item.id; modelId.value = item.id;
} }
// tab栏切换
// tab栏切换 性别
// tab栏切换 横竖比例 videoType==1为竖,==2为横
const tabSex = ref(0);
const tabVideoType = ref(0);
function changeTabSex(index) { function changeTabSex(index) {
modeList.value = []; modeList.value = [];
modelPageNum.value = 1; modelPageNum.value = 1;
modelTabItemActive.value = index; modelTabItemActive.value = index;
overLoadModel.value = false; overLoadModel.value = false;
if (index == 0) {
getModeList("", modelPageNum.value, modelPageSize.value);
} else {
getModeList(index, modelPageNum.value, modelPageSize.value);
}
tabSex.value = index;
getModeList(index, modelPageNum.value, modelPageSize.value);
}
function changeTabVideoType(index) {
modeList.value = [];
modelPageNum.value = 1;
modelTabItemActive2.value = index;
overLoadModel.value = false;
tabVideoType.value = index;
getModeList(tabSex.value, modelPageNum.value, modelPageSize.value);
} }
// watch(tabSex, (newVal, oldVal) => {
// if (newVal == 0) {
// getModeList("", modelPageNum.value, modelPageSize.value);
// } else {
// }
// });

// function changeTabSex(index) {
// modeList.value = [];
// modelPageNum.value = 1;
// modelTabItemActive.value = index;
// overLoadModel.value = false;
// if (index == 0) {
// getModeList("", modelPageNum.value, modelPageSize.value);
// } else {
// getModeList(index, modelPageNum.value, modelPageSize.value);
// }
// }
// 触底刷新
async function loadMoreModel(params) { async function loadMoreModel(params) {
modelPageNum.value += 1; modelPageNum.value += 1;
if (modelTabItemActive.value == 0) { if (modelTabItemActive.value == 0) {
@@ -604,7 +684,10 @@ onMounted(async () => {
<style lang="scss" scoped> <style lang="scss" scoped>
.page { .page {
height: calc(100vh - 80px); height: calc(100vh - 80px);
// height: calc(100vh - 80px);
background-color: #fff; background-color: #fff;
border-radius: 30px 0 0 0;
overflow: hidden;
} }
.mask { .mask {
position: absolute; position: absolute;
@@ -623,16 +706,17 @@ onMounted(async () => {
position: absolute; position: absolute;
top: 0px; top: 0px;
left: 0px; left: 0px;
width: 90%;
width: 30%;
height: 100%; height: 100%;
padding: 30px; padding: 30px;
transition: all 0.3s; transition: all 0.3s;
background-color: #f1f2f6;
// background-color: #f1f2f6;
background-color: #454545;
z-index: 9; z-index: 9;
.openChooseModel, .openChooseModel,
.closeChooseModel { .closeChooseModel {
position: absolute; position: absolute;
top: 10px;
top: 50%;
width: 50px; width: 50px;
height: 20px; height: 20px;
z-index: 999; z-index: 999;
@@ -642,54 +726,97 @@ onMounted(async () => {
height: 100%; height: 100%;
} }
} }
.openChooseModel {
right: 0px;
}
.closeChooseModel {
right: -50px;
// 伸缩按钮
.shrinkBtn {
position: absolute;
top: 350px;
right: -40px;
width: 40px;
height: 100px;
line-height: 80px;
padding: 10px;
font-size: 30px;
background-color: #454545;
color: #fff;
&::before {
position: absolute;
top: -40px;
left: -0px;
content: "";
width: 0;
height: 0px;
border-top: 20px solid transparent;
border-right: 20px solid transparent;
border-bottom: 20px solid #454545;
border-left: 20px solid #454545;
}
&::after {
position: absolute;
bottom: -40px;
left: -0px;
content: "";
width: 0;
height: 0px;
border-top: 20px solid #454545;
border-right: 20px solid transparent;
border-bottom: 20px solid transparent;
border-left: 20px solid #454545;
}
} }

// tab栏 // tab栏
p {
color: #fff;
font-size: 16px;
padding: 0 20px;
}
.tab { .tab {
margin: auto; margin: auto;
margin-top: 10px; margin-top: 10px;
display: flex; display: flex;
width: 100%; width: 100%;
height: 50px;
background-color: #fff;
height: 40px;
// background-color: #fff;
margin-bottom: 10px; margin-bottom: 10px;
border-radius: 25px; border-radius: 25px;
color: #b9b9b9;
.tabItem { .tabItem {
flex: 1; flex: 1;
font-size: 16px;
text-align: center; text-align: center;
line-height: 50px;
border-radius: 25px;
line-height: 40px;
border-radius: 15px;
transition: all 0.3s; transition: all 0.3s;
cursor: pointer; cursor: pointer;
margin: 0 10px;
background-color: #000;
} }
.tabItemActive { .tabItemActive {
background-color: #000;
color: #fff;
background-color: #fff;
color: #000;
} }
} }
// 模版列表 // 模版列表
.modeListBox { .modeListBox {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: flex-start;
width: 100%; width: 100%;
height: calc(100% - 60px);
height: calc(100% - 180px);
padding: 20px; padding: 20px;
border-radius: 20px; border-radius: 20px;
background-color: #fff;
// background-color: #fff;
overflow: hidden; overflow: hidden;
overflow-y: scroll; overflow-y: scroll;
.modeListBoxItme { .modeListBoxItme {
position: relative; position: relative;
padding: 20px; padding: 20px;
width: 300px;
height: 300px;
background: rgba(0, 0, 0, 0.1);
width: 45%;
height: 110px;
margin: 0 10px 10px 0; margin: 0 10px 10px 0;
border-radius: 15px; border-radius: 15px;
// background: rgba(0, 0, 0, 0.1);
background-color: #fff;
z-index: 2; z-index: 2;
cursor: pointer; cursor: pointer;
img { img {
@@ -701,26 +828,13 @@ onMounted(async () => {
} }
.modeListBoxItmeActive { .modeListBoxItmeActive {
border: 3px solid #7264f5; border: 3px solid #7264f5;
// &::before {
// content: "";
// position: absolute;
// top: -5px;
// left: -5px;
// width: 310px;
// height: 310px;
// background: linear-gradient(
// 225deg,
// rgba(81, 217, 202, 1),
// rgba(114, 100, 245, 1)
// );
// border-radius: 16px;
// }
} }
} }
} }
.noModel { .noModel {
width: 0; width: 0;
padding: 0; padding: 0;
// opacity: 0;
} }
// 展示区 // 展示区
.showModelImgBox { .showModelImgBox {


+ 213
- 58
src/views/login/index.vue Dosyayı Görüntüle

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


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


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


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


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


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


<el-form-item prop="confirmPassword"> <el-form-item prop="confirmPassword">
<span class="p-2 text-white">
<span class="text-white">
<svg-icon icon-class="password" /> <svg-icon icon-class="password" />
</span> </span>
<el-input <el-input
@@ -221,7 +235,75 @@
</div> </div>
</div> </div>
</el-form> </el-form>
<!-- 忘记密码 -->
<!-- 注册账户之后输入短信验证码 isLogin == 6-->
<el-form
v-if="isLogin == 6"
ref="loginFormRef"
:model="loginData6"
: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="SMSCode">
<div class="text-white">
<svg-icon icon-class="user" />
</div>
<el-input
class="flex-1"
ref="email"
size="large"
v-model="loginData6.SMSCode"
:placeholder="$t('login.SMSCode')"
name="email"
/>
</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.signIn") }}</span>
</div>
</div>
</el-form>
<!-- 忘记密码 isLogin == 3-->
<el-form <el-form
v-if="isLogin == 3" v-if="isLogin == 3"
ref="loginFormRef" ref="loginFormRef"
@@ -229,15 +311,22 @@
:rules="loginRules" :rules="loginRules"
class="login-form" class="login-form"
> >
<div class="flex text-white items-center py-4">
<span class="text-2xl flex-1 text-center">{{
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.forgetPwdTitle") $t("login.title") + " " + $t("login.forgetPwdTitle")
}}</span> }}</span>
<lang-select style="color: #fff" />
<el-tooltip
class="box-item"
effect="dark"
:content="$t('navbar.LanguageChange')"
placement="top-start"
>
<lang-select class="navItem" style="color: #ffffff" />
</el-tooltip>
</div> </div>


<el-form-item prop="email"> <el-form-item prop="email">
<div class="p-2 text-white">
<div class="text-white">
<svg-icon icon-class="user" /> <svg-icon icon-class="user" />
</div> </div>
<el-input <el-input
@@ -249,6 +338,23 @@
name="email" name="email"
/> />
</el-form-item> </el-form-item>
<!-- 验证码 -->
<el-form-item prop="code">
<span class="text-white">
<svg-icon icon-class="verify_code" />
</span>
<el-input
v-model="loginData3.code"
auto-complete="off"
:placeholder="$t('login.verifyCode')"
class="flex-1"
@keyup.enter="handleLogin"
/>

<span class="captcha">
<img v-if="showCodeImg" :src="verifyCodeUrl" @click="getCode" />
</span>
</el-form-item>


<el-button <el-button
size="default" size="default"
@@ -282,7 +388,7 @@
</div> </div>
</div> </div>
</el-form> </el-form>
<!-- 重置密码 -->
<!-- 重置密码 isLogin == 4-->
<el-form <el-form
v-if="isLogin == 4" v-if="isLogin == 4"
ref="loginFormRef" ref="loginFormRef"
@@ -290,22 +396,29 @@
:rules="loginRules" :rules="loginRules"
class="login-form" class="login-form"
> >
<div class="flex text-white items-center py-4">
<span class="text-2xl flex-1 text-center">{{
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.resetPassword") $t("login.title") + " " + $t("login.resetPassword")
}}</span> }}</span>
<lang-select style="color: #fff" />
<el-tooltip
class="box-item"
effect="dark"
:content="$t('navbar.LanguageChange')"
placement="top-start"
>
<lang-select class="navItem" style="color: #ffffff" />
</el-tooltip>
</div> </div>


<el-form-item prop="oldPassword">
<span class="p-2 text-white">
<el-form-item prop="verifyCode">
<span class="text-white">
<svg-icon icon-class="password" /> <svg-icon icon-class="password" />
</span> </span>
<el-input <el-input
class="flex-1" class="flex-1"
v-model="loginData4.oldPassword"
:placeholder="$t('login.oldPwd')"
:type="passwordVisible === false ? 'password' : 'input'"
v-model="loginData4.verifyCode"
:placeholder="$t('login.SMSCode')"
:type="'input'"
size="large" size="large"
name="password" name="password"
/> />
@@ -318,7 +431,7 @@
</el-form-item> </el-form-item>


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


<el-form-item prop="confirmPassword4"> <el-form-item prop="confirmPassword4">
<span class="p-2 text-white">
<span class="text-white">
<svg-icon icon-class="password" /> <svg-icon icon-class="password" />
</span> </span>
<el-input <el-input
@@ -387,16 +500,16 @@
<div style="margin-bottom: 5px" @click="loginFlag(1)"> <div style="margin-bottom: 5px" @click="loginFlag(1)">
<span class="join">{{ $t("login.signIn") }}</span> <span class="join">{{ $t("login.signIn") }}</span>
</div> </div>
<div>
<!-- <div>
<span <span
class="join" class="join"
@click="router.push({ path: 'createVideo', params: {} })" @click="router.push({ path: 'createVideo', params: {} })"
>{{ $t("login.gohome") }}</span >{{ $t("login.gohome") }}</span
> >
</div>
</div> -->
</div> </div>
</el-form> </el-form>
<!-- 忘记密码邮件返回 -->
<!-- 忘记密码邮件返回 isLogin == 5-->
<el-form <el-form
v-if="isLogin == 5" v-if="isLogin == 5"
ref="loginFormRef" ref="loginFormRef"
@@ -404,15 +517,22 @@
:rules="loginRules" :rules="loginRules"
class="login-form" class="login-form"
> >
<div class="flex text-white items-center py-4">
<span class="text-2xl flex-1 text-center">{{
<div class="flex text-white items-center">
<span class="flex-1 text-center">{{
$t("login.title") + " " + $t("login.setNewPwd") $t("login.title") + " " + $t("login.setNewPwd")
}}</span> }}</span>
<lang-select style="color: #fff" />
<el-tooltip
class="box-item"
effect="dark"
:content="$t('navbar.LanguageChange')"
placement="top-start"
>
<lang-select class="navItem" style="color: #ffffff" />
</el-tooltip>
</div> </div>


<el-form-item prop="newPwd"> <el-form-item prop="newPwd">
<div class="p-2 text-white">
<div class="text-white">
<svg-icon icon-class="password" /> <svg-icon icon-class="password" />
</div> </div>
<el-input <el-input
@@ -432,7 +552,7 @@
</span> </span>
</el-form-item> </el-form-item>
<el-form-item prop="confirmNewPwd"> <el-form-item prop="confirmNewPwd">
<div class="p-2 text-white">
<div class="text-white">
<svg-icon icon-class="password" /> <svg-icon icon-class="password" />
</div> </div>
<el-input <el-input
@@ -496,6 +616,7 @@ import {
sendRegisterEmail, sendRegisterEmail,
getCodeImgUrl, getCodeImgUrl,
sendUpdPwdEmailApi, sendUpdPwdEmailApi,
doUpdPassApi,
resetPwdEmailApi, resetPwdEmailApi,
resetPwdFormApi, resetPwdFormApi,
} from "@/apis/login"; } from "@/apis/login";
@@ -560,9 +681,10 @@ const loginData2 = ref({
}); });
const loginData3 = ref({ const loginData3 = ref({
email: "", email: "",
code: "",
}); });
const loginData4 = ref({ const loginData4 = ref({
oldPassword: "",
verifyCode: "",
password: "", password: "",
confirmPassword4: "", confirmPassword4: "",
}); });
@@ -570,6 +692,9 @@ const loginData5 = ref({
newPwd: "", newPwd: "",
confirmNewPwd: "", confirmNewPwd: "",
}); });
const loginData6 = ref({
SMSCode: "",
});


const loginRules = ref({ const loginRules = ref({
email: [ email: [
@@ -636,7 +761,7 @@ function loginFlag(type: number) {
*/ */
function saveInfo(data: any) { function saveInfo(data: any) {
const userInfo = JSON.stringify({ const userInfo = JSON.stringify({
email: data.email,
email: data.phone,
password: data.password, password: data.password,
}); });
// 将用户信息加密 // 将用户信息加密
@@ -665,18 +790,21 @@ function getInfo() {
function emailValidator(rule: any, value: any, callback: any) { function emailValidator(rule: any, value: any, callback: any) {
const msg = const msg =
currentLan.value == "zh-cn" currentLan.value == "zh-cn"
? "邮箱不能为空!"
? "手机号不能为空!"
: "The E-amil can not be empty"; : "The E-amil can not be empty";


const msg2 = const msg2 =
currentLan.value == "zh-cn" ? "邮箱格式不正确!" : "Incorrect email format";
currentLan.value == "zh-cn"
? "手机号格式不正确!"
: "Incorrect email format";


const phoneReg = /^[1][3-9]\d{9}$/;
const emailReg = 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,}))$/; /^(([^<>()[\]\\.,;:\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,}))$/;


if (!value) { if (!value) {
callback(new Error(msg)); callback(new Error(msg));
} else if (!emailReg.test(value)) {
} else if (!phoneReg.test(value)) {
callback(new Error(msg2)); callback(new Error(msg2));
} else { } else {
callback(); callback();
@@ -773,7 +901,7 @@ function handleLogin() {
loginFormRef.value.validate((val: any) => { loginFormRef.value.validate((val: any) => {
if (val) { if (val) {
const data = { const data = {
email: loginData.value.email,
phone: loginData.value.email,
password: loginData.value.password, password: loginData.value.password,
code: loginData.value.verifyCode, code: loginData.value.verifyCode,
}; };
@@ -795,7 +923,7 @@ function handleRegister() {
loginFormRef.value.validate((val: any) => { loginFormRef.value.validate((val: any) => {
if (val) { if (val) {
const data = { const data = {
email: loginData2.value.email,
phone: loginData2.value.email,
password: loginData2.value.password, password: loginData2.value.password,
}; };
isRegistering.value = true; isRegistering.value = true;
@@ -815,17 +943,19 @@ function handleRegister() {
function sendEmailforgetPwd() { function sendEmailforgetPwd() {
const msg = const msg =
currentLan.value == "zh-cn" currentLan.value == "zh-cn"
? "确认信息已发送至您的邮箱,请注意查收"
: "An email has been send to you, Please pay attention to confirm";
? "短信验证码已发送至您的手机,请注意查收"
: "The SMS verification code has been sent to your mobile phone, please check it";
loginFormRef.value.validate(async (val: any) => { loginFormRef.value.validate(async (val: any) => {
if (val) { if (val) {
const data = { const data = {
email: loginData3.value.email,
phone: loginData3.value.email,
code: loginData3.value.code,
}; };
await sendUpdPwdEmailApi(data.email)
await sendUpdPwdEmailApi(data)
.then((res) => { .then((res) => {
console.log(res, "res"); console.log(res, "res");
ElMessage.success(msg); ElMessage.success(msg);
isLogin.value = 4;
}) })
.catch((err) => { .catch((err) => {
console.log(err, "err"); console.log(err, "err");
@@ -878,14 +1008,20 @@ function resetPwdForm() {
loginFormRef.value.validate(async (val: any) => { loginFormRef.value.validate(async (val: any) => {
if (val) { if (val) {
try { try {
const res = await resetPwdFormApi({
oldpwd: loginData4.value.oldPassword,
newpwd: loginData4.value.password,
const res = await doUpdPassApi({
phone: loginData3.value.email,
code: loginData4.value.verifyCode,
pwd: loginData4.value.password,
}); });
localStorage.removeItem("AccessToken"); localStorage.removeItem("AccessToken");
loginData.value.password = ""; loginData.value.password = "";
isLogin.value = 1; isLogin.value = 1;
router.push({ path: "login", query: {} });
ElMessage.success(
currentLan.value == "zh-cn"
? "重置密码成功!"
: "Reset password successfully"
);
// router.push({ path: "login", query: {} });
} catch (error: any) { } catch (error: any) {
ElMessage.error(error.message); ElMessage.error(error.message);
console.log(error); console.log(error);
@@ -920,16 +1056,16 @@ function getCode() {
*/ */
async function doRegister(data: object) { async function doRegister(data: object) {
const msg = const msg =
currentLan.value == "zh-cn"
? "确认信息已发送至您的邮箱,请注意查收"
: "An email has been send to you, Please pay attention to confirm";
currentLan.value == "zh-cn" ? "注册成功!" : "Registered successfully";
await register(data) await register(data)
.then((res) => { .then((res) => {
console.log(res, "res"); console.log(res, "res");
isRegistering.value = false; isRegistering.value = false;
ElMessage.success(msg); ElMessage.success(msg);
isLogin.value = 1;
// 注册成功将账号密码保存到本地 // 注册成功将账号密码保存到本地
saveInfo(data); saveInfo(data);
router.go(0);
}) })
.catch((err) => { .catch((err) => {
// 注册失败刷新验证码 // 注册失败刷新验证码
@@ -996,8 +1132,16 @@ onMounted(() => {
getCode(); getCode();
getInfo(); getInfo();
// 重置密码 // 重置密码
if (router.currentRoute.value.params.type) {
isLogin.value = Number(router.currentRoute.value.params.type);
// if (router.currentRoute.value.params.type) {
// // isLogin.value = Number(router.currentRoute.value.params.type);
// isLogin.value = 4;
// }
// if (router.currentRoute.value.params.type) {
// // isLogin.value = Number(router.currentRoute.value.params.type);
// isLogin.value = 4;
// }
if (route.query.type) {
isLogin.value = 4;
} }
//有resetPwd则说明是重置密码邮件来的 //有resetPwd则说明是重置密码邮件来的
if (route.query.resetPwd) { if (route.query.resetPwd) {
@@ -1011,6 +1155,8 @@ onMounted(() => {
.login-container { .login-container {
position: relative; position: relative;
width: 100%; width: 100%;
// width: 1920px;
// height: 1080px;
min-height: 100%; min-height: 100%;
overflow: hidden; overflow: hidden;
// background-color: #2d3a4b; // background-color: #2d3a4b;
@@ -1055,6 +1201,15 @@ onMounted(() => {
&:hover { &:hover {
backdrop-filter: blur(7px); backdrop-filter: blur(7px);
} }
.items-center {
padding: 20px;
font-size: 30px;
}
.el-form-item {
.text-white {
padding: 8px;
}
}
} }
} }




+ 42
- 0
src/views/moveImg/index.vue Dosyayı Görüntüle

@@ -18,6 +18,11 @@
alt="" alt=""
/> />
</div> </div>
<div class="container">
<div class="box red"></div>
<div class="box white"></div>
<div class="box green"></div>
</div>
</div> </div>
</template> </template>


@@ -93,3 +98,40 @@ onMounted(() => {
} }
} }
</style> </style>

<style lang="scss" scoped>
.container {
display: flex;
align-items: center;
justify-content: space-between;
width: 80px;
height: 20px;
perspective: 500px;
transition: transform 0.5s;
}

.box {
width: 20px;
height: 20px;
transition: transform 0.5s;
transform-style: preserve-3d;
}

.red {
background-color: red;
}

.white {
background-color: white;
transform: translateZ(20px);
}

.green {
background-color: green;
transform: translateZ(-20px);
}

.container:hover .box {
transform: rotateY(180deg);
}
</style>

Yükleniyor…
İptal
Kaydet