<template> <div :class="prefixCls" class="h-[100%] relative <xl:bg-v-dark <sm:px-10px <xl:px-10px <md:px-10px" > <div class="relative h-full flex mx-auto"> <div :class="`${prefixCls}__left flex-1 bg-gray-500 bg-opacity-20 relative p-30px <xl:hidden`" > <!-- 左上角的 logo + 系统标题 --> <div class="flex items-center relative text-white"> <img alt="" class="w-48px h-48px mr-10px" src="@/assets/imgs/logo.png" /> <span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span> </div> <!-- 左边的背景图 + 欢迎语 --> <div class="flex justify-center"> <TransitionGroup appear enter-active-class="animate__animated animate__bounceInLeft" tag="div" > <img key="1" alt="" class="w-350px" src="@/assets/svgs/login-box-bg.svg" /> <!-- <div key="2" class="text-3xl text-white">{{ t('login.welcome') }}</div> --> </TransitionGroup> </div> <div class="landIn"> <transition-group name="text-animation"> <span v-for="(char, index) in chars" :key="index">{{ char }}</span> </transition-group> </div> </div> <div class="flex-1 p-30px <sm:p-10px dark:bg-v-dark relative"> <!-- 右上角的主题、语言选择 --> <div class="flex justify-between items-center text-white @2xl:justify-end @xl:justify-end"> <div class="flex items-center @2xl:hidden @xl:hidden"> <img alt="" class="w-48px h-48px mr-10px" src="@/assets/imgs/logo.png" /> <span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span> </div> <div class="flex justify-end items-center space-x-10px"> <ThemeSwitch /> <!-- <LocaleDropdown class="<xl:text-white dark:text-white" /> --> </div> </div> <!-- 右边的登录界面 --> <Transition appear enter-active-class="animate__animated animate__bounceInRight"> <div class="h-full flex items-center m-auto w-[100%] @2xl:max-w-500px @xl:max-w-500px @md:max-w-500px @lg:max-w-500px" > <!-- 账号登录 --> <LoginForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" /> <!-- 手机登录 --> <MobileForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" /> <!-- 二维码登录 --> <QrCodeForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" /> <!-- 注册 --> <!-- <RegisterForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" /> --> <!-- 三方登录 --> <!-- <SSOLoginVue class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" /> --> </div> </Transition> </div> </div> </div> </template> <script lang="ts" name="Login" setup> import { underlineToHump } from '@/utils' import { useDesign } from '@/hooks/web/useDesign' import { useAppStore } from '@/store/modules/app' import { ThemeSwitch } from '@/layout/components/ThemeSwitch' import { LoginForm, MobileForm, QrCodeForm } from './components' import soups from './components/soup.js' // const { t } = useI18n() const appStore = useAppStore() const { getPrefixCls } = useDesign() const prefixCls = getPrefixCls('login') const currentCharIndex = ref(0) const typingInterval = ref(null) const randomIdx = parseInt(soups.length * Math.random()) const text = soups[randomIdx] const chars = computed(() => { // return t('login.message') return text.slice(0, currentCharIndex.value) }) onMounted(() => { startTyping() }) function startTyping() { typingInterval.value = setInterval(() => { if (currentCharIndex.value < text.length) { currentCharIndex.value++ } else { clearInterval(typingInterval.value) } }, 100) // 每100毫秒展示一个字符 } </script> <style lang="scss" scoped> $prefix-cls: #{$namespace}-login; .#{$prefix-cls} { &__left { &::before { position: absolute; top: 0; left: 0; z-index: -1; width: 100%; height: 100%; background-image: url('@/assets/svgs/login-bg.svg'); background-position: center; background-repeat: no-repeat; content: ''; } } } .text-animation-enter-active, .text-animation-leave-active { transition: opacity 0.5s; } .text-animation-enter, .text-animation-leave-to { opacity: 0; } .landIn { margin: 10px auto; width: 80%; display: flex; flex-wrap: wrap; font-size: 18px; line-height: 1.8; font-family: Lora, serif; white-space: pre; font-weight: 600; color: #6ee1f5; span { animation: landIn 0.8s ease-out both; } } @keyframes landIn { from { opacity: 0; transform: translateY(-30%); } to { opacity: 1; transform: translateY(0); } } </style>