mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-23 23:39:47 +08:00
feat(projects): 重构登录页面样式
This commit is contained in:
@ -1,61 +1,524 @@
|
|||||||
|
<!-- Copyright By https://github.com/Daymychen/art-design-pro/blob/main/src/components/core/views/login/LoginLeftView.vue -->
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue';
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
import { getPaletteColorByNumber } from '@sa/color';
|
|
||||||
|
|
||||||
defineOptions({ name: 'WaveBg' });
|
defineOptions({ name: 'WaveBg' });
|
||||||
|
|
||||||
interface Props {
|
const themeStore = useThemeStore();
|
||||||
/** Theme color */
|
|
||||||
themeColor: string;
|
function toggleThemeScheme() {
|
||||||
|
if (themeStore.darkMode) {
|
||||||
|
themeStore.setThemeScheme('light');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
themeStore.setThemeScheme('dark');
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
|
||||||
|
|
||||||
const lightColor = computed(() => getPaletteColorByNumber(props.themeColor, 200));
|
|
||||||
const darkColor = computed(() => getPaletteColorByNumber(props.themeColor, 500));
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="absolute-lt z-1 size-full overflow-hidden">
|
<div class="wave-bg">
|
||||||
<div class="absolute -right-300px -top-900px lt-sm:(-right-100px -top-1170px)">
|
<!-- 几何装饰元素 -->
|
||||||
<svg height="1337" width="1337">
|
<div class="geometric-decorations">
|
||||||
<defs>
|
<!-- 基础几何形状 -->
|
||||||
<path
|
<div class="geo-element circle-outline animate-fade-in-up animate-delay-0s"></div>
|
||||||
id="path-1"
|
<div class="geo-element square-rotated animate-fade-in-left animate-delay-0s"></div>
|
||||||
opacity="1"
|
<div class="geo-element circle-small animate-fade-in-up animate-delay-0.3s"></div>
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M1337,668.5 C1337,1037.455193874239 1037.455193874239,1337 668.5,1337 C523.6725684305388,1337 337,1236 370.50000000000006,1094 C434.03835568300906,824.6732385973953 6.906089672974592e-14,892.6277623047779 0,668.5000000000001 C0,299.5448061257611 299.5448061257609,1.1368683772161603e-13 668.4999999999999,0 C1037.455193874239,0 1337,299.544806125761 1337,668.5Z"
|
<div class="geo-element square-bottom-right animate-fade-in-right animate-delay-0s"></div>
|
||||||
/>
|
|
||||||
<linearGradient id="linearGradient-2" x1="0.79" y1="0.62" x2="0.21" y2="0.86">
|
<!-- 背景泡泡 -->
|
||||||
<stop offset="0" :stop-color="lightColor" stop-opacity="1" />
|
<div class="geo-element bg-bubble animate-scale-in animate-delay-0.5s"></div>
|
||||||
<stop offset="1" :stop-color="darkColor" stop-opacity="1" />
|
|
||||||
</linearGradient>
|
<!-- 太阳/月亮 -->
|
||||||
</defs>
|
<div
|
||||||
<g opacity="1">
|
class="geo-element circle-top-right animate-fade-in-down animate-delay-0.5s"
|
||||||
<use xlink:href="#path-1" fill="url(#linearGradient-2)" fill-opacity="1" />
|
@click="toggleThemeScheme"
|
||||||
</g>
|
></div>
|
||||||
</svg>
|
|
||||||
</div>
|
<!-- 装饰点 -->
|
||||||
<div class="absolute -bottom-400px -left-200px lt-sm:(-bottom-760px -left-100px)">
|
<div class="geo-element dot dot-top-left animate-bounce-in animate-delay-0s"></div>
|
||||||
<svg height="896" width="967.8852157128662">
|
<div class="geo-element dot dot-top-right animate-bounce-in animate-delay-0s"></div>
|
||||||
<defs>
|
<div class="geo-element dot dot-center-right animate-bounce-in animate-delay-0s"></div>
|
||||||
<path
|
|
||||||
id="path-2"
|
<!-- 叠加方块组 -->
|
||||||
opacity="1"
|
<div class="squares-group">
|
||||||
fill-rule="evenodd"
|
<i class="geo-element square square-blue animate-fade-in-left-rotated-blue animate-delay-0.2s"></i>
|
||||||
d="M896,448 C1142.6325445712241,465.5747656464056 695.2579309733121,896 448,896 C200.74206902668806,896 5.684341886080802e-14,695.2579309733121 0,448.0000000000001 C0,200.74206902668806 200.74206902668791,5.684341886080802e-14 447.99999999999994,0 C695.2579309733121,0 475,418 896,448Z"
|
<i class="geo-element square square-pink animate-fade-in-left-rotated-pink animate-delay-0.4s"></i>
|
||||||
/>
|
<i class="geo-element square square-purple animate-fade-in-left-no-rotation animate-delay-0.6s"></i>
|
||||||
<linearGradient id="linearGradient-3" x1="0.5" y1="0" x2="0.5" y2="1">
|
</div>
|
||||||
<stop offset="0" :stop-color="darkColor" stop-opacity="1" />
|
|
||||||
<stop offset="1" :stop-color="lightColor" stop-opacity="1" />
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<g opacity="1">
|
|
||||||
<use xlink:href="#path-2" fill="url(#linearGradient-3)" fill-opacity="1" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style lang="scss" scoped>
|
||||||
|
// 颜色变量定义
|
||||||
|
$primary-light-7: rgb(var(--primary-50-color));
|
||||||
|
$primary-light-8: rgb(var(--primary-100-color));
|
||||||
|
$primary-light-9: rgb(var(--primary-200-color));
|
||||||
|
$primary-base: rgb(var(--primary-color));
|
||||||
|
$main-bg: rgb(var(--primary-50-color));
|
||||||
|
|
||||||
|
// 混合颜色函数
|
||||||
|
$bg-mix-light-9: color-mix(in srgb, $primary-light-9 100%, $main-bg);
|
||||||
|
$bg-mix-light-8: color-mix(in srgb, $primary-light-8 80%, $main-bg);
|
||||||
|
$bg-mix-light-7: color-mix(in srgb, $primary-light-7 80%, $main-bg);
|
||||||
|
|
||||||
|
.wave-bg {
|
||||||
|
.geometric-decorations {
|
||||||
|
.geo-element {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
animation-duration: 0.8s;
|
||||||
|
animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动画 mixin
|
||||||
|
@mixin fadeAnimation($direction: '', $rotation: 0deg) {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
@if $direction == 'up' {
|
||||||
|
transform: translateY(30px) rotate($rotation);
|
||||||
|
} @else if $direction == 'down' {
|
||||||
|
transform: translateY(-30px) rotate($rotation);
|
||||||
|
} @else if $direction == 'left' {
|
||||||
|
transform: translateX(-30px) rotate($rotation);
|
||||||
|
} @else if $direction == 'right' {
|
||||||
|
transform: translateX(30px) rotate($rotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
@if $direction == 'up' or $direction == 'down' {
|
||||||
|
transform: translateY(0) rotate($rotation);
|
||||||
|
} @else {
|
||||||
|
transform: translateX(0) rotate($rotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动画定义
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
@include fadeAnimation('up');
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInDown {
|
||||||
|
@include fadeAnimation('down');
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInLeft {
|
||||||
|
@include fadeAnimation('left');
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInLeftRotated {
|
||||||
|
@include fadeAnimation('left', -25deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInRight {
|
||||||
|
@include fadeAnimation('right');
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInRightRotated {
|
||||||
|
@include fadeAnimation('right', 45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInLeftRotatedBlue {
|
||||||
|
@include fadeAnimation('left', -10deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInLeftRotatedPink {
|
||||||
|
@include fadeAnimation('left', 10deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInLeftNoRotation {
|
||||||
|
@include fadeAnimation('left');
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scaleIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bounceIn {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
70% {
|
||||||
|
transform: scale(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes lineGrow {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideInLeft {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动画类
|
||||||
|
.animate-fade-in-up {
|
||||||
|
animation-name: fadeInUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in-down {
|
||||||
|
animation-name: fadeInDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in-left {
|
||||||
|
animation-name: fadeInLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in-right {
|
||||||
|
animation-name: fadeInRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-scale-in {
|
||||||
|
animation-name: scaleIn;
|
||||||
|
animation-duration: 1.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-bounce-in {
|
||||||
|
animation-name: bounceIn;
|
||||||
|
animation-duration: 0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in-left-rotated-blue {
|
||||||
|
animation-name: fadeInLeftRotatedBlue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in-left-rotated-pink {
|
||||||
|
animation-name: fadeInLeftRotatedPink;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in-left-no-rotation {
|
||||||
|
animation-name: fadeInLeftNoRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基础几何形状
|
||||||
|
.circle-outline {
|
||||||
|
top: 10%;
|
||||||
|
left: 25%;
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
border: 2px solid $primary-light-8;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.square-rotated {
|
||||||
|
top: 50%;
|
||||||
|
left: 16%;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
background-color: $bg-mix-light-8;
|
||||||
|
|
||||||
|
&.animate-fade-in-left {
|
||||||
|
animation-name: fadeInLeftRotated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle-small {
|
||||||
|
bottom: 26%;
|
||||||
|
left: 30%;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
background-color: $primary-light-8;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 太阳/月亮效果
|
||||||
|
.circle-top-right {
|
||||||
|
top: 3%;
|
||||||
|
right: 3%;
|
||||||
|
z-index: 100;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: $bg-mix-light-7;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
content: '';
|
||||||
|
background: linear-gradient(to right, #fcbb04, #fffc00);
|
||||||
|
border-radius: 50%;
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.5s;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 36px #fffc00;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.square-bottom-right {
|
||||||
|
right: 10%;
|
||||||
|
bottom: 10%;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background-color: $primary-light-8;
|
||||||
|
|
||||||
|
&.animate-fade-in-right {
|
||||||
|
animation-name: fadeInRightRotated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 背景泡泡
|
||||||
|
.bg-bubble {
|
||||||
|
top: -120px;
|
||||||
|
right: -120px;
|
||||||
|
width: 360px;
|
||||||
|
height: 360px;
|
||||||
|
background-color: $bg-mix-light-8;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 装饰点
|
||||||
|
.dot {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
background-color: $primary-light-7;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
&.dot-top-left {
|
||||||
|
top: 140px;
|
||||||
|
left: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dot-top-right {
|
||||||
|
top: 140px;
|
||||||
|
right: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dot-center-right {
|
||||||
|
top: 46%;
|
||||||
|
right: 22%;
|
||||||
|
background-color: $primary-light-8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 叠加方块组
|
||||||
|
.squares-group {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 18px;
|
||||||
|
left: 20px;
|
||||||
|
width: 140px;
|
||||||
|
height: 140px;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
.square {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 8px 24px rgb(64 87 167 / 12%);
|
||||||
|
|
||||||
|
&.square-blue {
|
||||||
|
top: 12px;
|
||||||
|
left: 30px;
|
||||||
|
z-index: 2;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background-color: rgb(from $primary-base r g b / 30%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.square-pink {
|
||||||
|
top: 30px;
|
||||||
|
left: 48px;
|
||||||
|
z-index: 1;
|
||||||
|
width: 70px;
|
||||||
|
height: 70px;
|
||||||
|
background-color: rgb(from $primary-base r g b / 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.square-purple {
|
||||||
|
top: 66px;
|
||||||
|
left: 86px;
|
||||||
|
z-index: 3;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background-color: rgb(from $primary-base r g b / 45%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 装饰线条
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 86px;
|
||||||
|
left: 72px;
|
||||||
|
width: 80px;
|
||||||
|
height: 1px;
|
||||||
|
content: '';
|
||||||
|
background: linear-gradient(90deg, var(--el-color-primary-light-6), transparent);
|
||||||
|
opacity: 0;
|
||||||
|
transform: rotate(50deg);
|
||||||
|
animation: lineGrow 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
|
||||||
|
animation-delay: 1.2s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1600px) {
|
||||||
|
width: 60vw;
|
||||||
|
|
||||||
|
.text-wrap {
|
||||||
|
bottom: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1280px) {
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
padding: 0;
|
||||||
|
// 隐藏背景和其他内容,只保留 logo
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
.left-img,
|
||||||
|
.text-wrap,
|
||||||
|
.geometric-decorations {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
position: fixed;
|
||||||
|
top: 15px;
|
||||||
|
left: 25px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暗色主题
|
||||||
|
.dark .wave-bg {
|
||||||
|
background-color: color-mix(in srgb, $primary-light-9 60%, #070707);
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1280px) {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.geometric-decorations {
|
||||||
|
// 月亮效果
|
||||||
|
.circle-top-right {
|
||||||
|
background-color: $bg-mix-light-8;
|
||||||
|
box-shadow: 0 0 25px #333 inset;
|
||||||
|
transition: all 0.3s ease-in-out 0.1s;
|
||||||
|
rotate: -48deg;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 15px;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
content: '';
|
||||||
|
background-color: $bg-mix-light-9;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
box-shadow: 0 40px 25px #ddd inset;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
left: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-bubble {
|
||||||
|
background-color: $bg-mix-light-9;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他元素颜色调整
|
||||||
|
.square-rotated {
|
||||||
|
background-color: $bg-mix-light-9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle-small,
|
||||||
|
.dot {
|
||||||
|
background-color: $primary-light-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.square-bottom-right {
|
||||||
|
background-color: $primary-light-9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot.dot-top-right {
|
||||||
|
background-color: $primary-light-8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方块组暗色调整
|
||||||
|
.squares-group {
|
||||||
|
.square {
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
&.square-blue {
|
||||||
|
background-color: rgb(from $primary-base r g b / 18%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.square-pink {
|
||||||
|
background-color: rgb(from $primary-base r g b / 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.square-purple {
|
||||||
|
background-color: rgb(from $primary-base r g b / 20%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
background: linear-gradient(90deg, $primary-light-8, transparent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -328,6 +328,8 @@ const local: App.I18n.Schema = {
|
|||||||
page: {
|
page: {
|
||||||
login: {
|
login: {
|
||||||
common: {
|
common: {
|
||||||
|
title: 'Modern enterprise-level multi-tenant management system',
|
||||||
|
subTitle: 'Provides developers with a complete enterprise management solution',
|
||||||
loginOrRegister: 'Login / Register',
|
loginOrRegister: 'Login / Register',
|
||||||
register: 'Register',
|
register: 'Register',
|
||||||
userNamePlaceholder: 'Please enter user name',
|
userNamePlaceholder: 'Please enter user name',
|
||||||
|
@ -328,6 +328,8 @@ const local: App.I18n.Schema = {
|
|||||||
page: {
|
page: {
|
||||||
login: {
|
login: {
|
||||||
common: {
|
common: {
|
||||||
|
title: '现代化的企业级多租户管理系统',
|
||||||
|
subTitle: '为开发者提供了完整的企业管理解决方案',
|
||||||
loginOrRegister: '登录 / 注册',
|
loginOrRegister: '登录 / 注册',
|
||||||
register: '注册',
|
register: '注册',
|
||||||
userNamePlaceholder: '请输入用户名',
|
userNamePlaceholder: '请输入用户名',
|
||||||
|
@ -44,7 +44,7 @@ export const themeSettings: App.Theme.ThemeSetting = {
|
|||||||
fixedHeaderAndTab: true,
|
fixedHeaderAndTab: true,
|
||||||
sider: {
|
sider: {
|
||||||
inverted: false,
|
inverted: false,
|
||||||
width: 220,
|
width: 230,
|
||||||
collapsedWidth: 64,
|
collapsedWidth: 64,
|
||||||
mixWidth: 90,
|
mixWidth: 90,
|
||||||
mixCollapsedWidth: 64,
|
mixCollapsedWidth: 64,
|
||||||
|
2
src/typings/app.d.ts
vendored
2
src/typings/app.d.ts
vendored
@ -487,6 +487,8 @@ declare namespace App {
|
|||||||
};
|
};
|
||||||
login: {
|
login: {
|
||||||
common: {
|
common: {
|
||||||
|
title: string;
|
||||||
|
subTitle: string;
|
||||||
loginOrRegister: string;
|
loginOrRegister: string;
|
||||||
register: string;
|
register: string;
|
||||||
userNamePlaceholder: string;
|
userNamePlaceholder: string;
|
||||||
|
@ -39,45 +39,51 @@ const activeModule = computed(() => moduleMap[props.module || 'pwd-login']);
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="relative min-h-screen w-full flex flex-wrap">
|
<!-- Copyright By https://github.com/Daymychen/art-design-pro/blob/main/src/components/core/views/login/LoginLeftView.vue -->
|
||||||
<div class="hidden min-h-screen w-50% bg-primary-100 lg:block dark:bg-primary-800">
|
<div class="box-border size-full flex">
|
||||||
<div class="size-full flex-center">
|
<div class="relative box-border hidden h-full w-65vw overflow-hidden bg-primary-50 xl:block dark:bg-primary-900">
|
||||||
<img class="w-60% sm:w-80%" :src="loginBackground" />
|
<div class="relative z-100 flex items-center pl-30px pt-30px">
|
||||||
|
<SystemLogo class="text-32px text-primary" />
|
||||||
|
<h3 class="ml-10px text-20px font-400">{{ $t('system.title') }}</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="absolute inset-x-0 inset-b-10.5% inset-t-0 z-10 m-auto w-40%">
|
||||||
<div class="w-full flex-col-center px-24px py-32px lg:w-50%">
|
<img class="size-full" :src="loginBackground" />
|
||||||
<div class="mx-auto max-w-464px w-full">
|
|
||||||
<header class="flex-y-center justify-between">
|
|
||||||
<div class="flex-y-center gap-16px">
|
|
||||||
<SystemLogo class="text-30px text-primary sm:text-42px" />
|
|
||||||
<h3 class="text-24px text-primary font-500 sm:text-32px">{{ $t('system.title') }}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="flex-y-center">
|
|
||||||
<ThemeSchemaSwitch
|
|
||||||
:theme-schema="themeStore.themeScheme"
|
|
||||||
:show-tooltip="false"
|
|
||||||
class="text-20px lt-sm:text-18px"
|
|
||||||
@switch="themeStore.toggleThemeScheme"
|
|
||||||
/>
|
|
||||||
<LangSwitch
|
|
||||||
v-if="themeStore.header.multilingual.visible"
|
|
||||||
:lang="appStore.locale"
|
|
||||||
:lang-options="appStore.localeOptions"
|
|
||||||
:show-tooltip="false"
|
|
||||||
class="text-20px lt-sm:text-18px"
|
|
||||||
@change-lang="appStore.changeLocale"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<main class="pt-24px">
|
|
||||||
<div>
|
|
||||||
<Transition :name="themeStore.page.animateMode" mode="out-in" appear>
|
|
||||||
<component :is="activeModule.component" />
|
|
||||||
</Transition>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="absolute bottom-80px w-full text-center">
|
||||||
|
<h1 class="text-24px font-400">{{ $t('page.login.common.title') }}</h1>
|
||||||
|
<p class="mt-8px text-14px color-gray-500">{{ $t('page.login.common.subTitle') }}</p>
|
||||||
|
</div>
|
||||||
|
<WaveBg />
|
||||||
</div>
|
</div>
|
||||||
|
<header class="relative h-full flex-1 xl:m-auto sm:!w-full">
|
||||||
|
<div class="relative z-100 block flex items-center pl-30px pt-30px xl:hidden">
|
||||||
|
<SystemLogo class="text-32px text-primary" />
|
||||||
|
<h3 class="ml-10px text-20px font-400">{{ $t('system.title') }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="position-fixed right-30px top-24px z-100 flex items-center justify-end">
|
||||||
|
<div class="ml-15px inline-block flex cursor-pointer select-none p-5px">
|
||||||
|
<ThemeSchemaSwitch
|
||||||
|
:theme-schema="themeStore.themeScheme"
|
||||||
|
:show-tooltip="false"
|
||||||
|
class="text-20px lt-sm:text-18px"
|
||||||
|
@switch="themeStore.toggleThemeScheme"
|
||||||
|
/>
|
||||||
|
<LangSwitch
|
||||||
|
v-if="themeStore.header.multilingual.visible"
|
||||||
|
:lang="appStore.locale"
|
||||||
|
:lang-options="appStore.localeOptions"
|
||||||
|
:show-tooltip="false"
|
||||||
|
class="text-20px lt-sm:text-18px"
|
||||||
|
@change-lang="appStore.changeLocale"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<main class="absolute inset-0 m-auto h-630px max-w-450px w-full overflow-hidden rounded-5px bg-cover px-24px">
|
||||||
|
<Transition :name="themeStore.page.animateMode" mode="out-in" appear>
|
||||||
|
<component :is="activeModule.component" />
|
||||||
|
</Transition>
|
||||||
|
</main>
|
||||||
|
</header>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -40,6 +40,10 @@ async function handleSubmit() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<div class="mb-5px text-32px text-black font-600 sm:text-30px dark:text-white">
|
||||||
|
{{ $t('page.login.codeLogin.title') }}
|
||||||
|
</div>
|
||||||
|
<div class="pb-18px text-16px text-#858585">请输入您的手机号,我们将发送验证码到您的手机</div>
|
||||||
<NForm ref="formRef" :model="model" :rules="rules" size="large" :show-label="false" @keyup.enter="handleSubmit">
|
<NForm ref="formRef" :model="model" :rules="rules" size="large" :show-label="false" @keyup.enter="handleSubmit">
|
||||||
<NFormItem path="phone">
|
<NFormItem path="phone">
|
||||||
<NInput v-model:value="model.phone" :placeholder="$t('page.login.common.phonePlaceholder')" />
|
<NInput v-model:value="model.phone" :placeholder="$t('page.login.common.phonePlaceholder')" />
|
||||||
@ -52,15 +56,32 @@ async function handleSubmit() {
|
|||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NSpace vertical :size="18" class="w-full">
|
<NSpace vertical :size="20" class="w-full">
|
||||||
<NButton type="primary" size="large" round block @click="handleSubmit">
|
<NButton type="primary" size="large" block @click="handleSubmit">
|
||||||
{{ $t('common.confirm') }}
|
{{ $t('page.login.codeLogin.title') }}
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton size="large" round block @click="toggleLoginModule('pwd-login')">
|
<NButton size="large" block @click="toggleLoginModule('pwd-login')">
|
||||||
{{ $t('page.login.common.back') }}
|
{{ $t('page.login.common.back') }}
|
||||||
</NButton>
|
</NButton>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
</NForm>
|
</NForm>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped>
|
||||||
|
:deep(.n-base-selection),
|
||||||
|
:deep(.n-input) {
|
||||||
|
--n-height: 42px !important;
|
||||||
|
--n-font-size: 16px !important;
|
||||||
|
--n-border-radius: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.n-base-selection-label) {
|
||||||
|
padding: 0 6px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.n-button) {
|
||||||
|
--n-height: 42px !important;
|
||||||
|
--n-font-size: 18px !important;
|
||||||
|
--n-border-radius: 8px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -124,8 +124,8 @@ async function handleSocialLogin(type: Api.System.SocialSource) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="mb-12px text-24px text-black font-500 sm:text-30px dark:text-white">登录到您的账户</div>
|
<div class="mb-5px text-32px text-black font-600 dark:text-white">登录到您的账户</div>
|
||||||
<div class="pb-24px text-18px text-#858585">欢迎回来!请输入您的账户信息</div>
|
<div class="pb-18px text-16px text-#858585">欢迎回来!请输入您的账户信息</div>
|
||||||
<NForm
|
<NForm
|
||||||
ref="formRef"
|
ref="formRef"
|
||||||
:model="model"
|
:model="model"
|
||||||
@ -156,16 +156,16 @@ async function handleSocialLogin(type: Api.System.SocialSource) {
|
|||||||
<NFormItem v-if="captchaEnabled" path="code">
|
<NFormItem v-if="captchaEnabled" path="code">
|
||||||
<div class="w-full flex-y-center gap-16px">
|
<div class="w-full flex-y-center gap-16px">
|
||||||
<NInput v-model:value="model.code" :placeholder="$t('page.login.common.codePlaceholder')" />
|
<NInput v-model:value="model.code" :placeholder="$t('page.login.common.codePlaceholder')" />
|
||||||
<NSpin :show="codeLoading" :size="28" class="h-52px">
|
<NSpin :show="codeLoading" :size="28" class="h-42px">
|
||||||
<NButton :focusable="false" class="login-code h-52px w-136px" @click="handleFetchCaptchaCode">
|
<NButton :focusable="false" class="login-code h-42px w-136px" @click="handleFetchCaptchaCode">
|
||||||
<img v-if="codeUrl" :src="codeUrl" />
|
<img v-if="codeUrl" :src="codeUrl" />
|
||||||
<NEmpty v-else :show-icon="false" description="暂无验证码" />
|
<NEmpty v-else :show-icon="false" description="暂无验证码" />
|
||||||
</NButton>
|
</NButton>
|
||||||
</NSpin>
|
</NSpin>
|
||||||
</div>
|
</div>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NSpace vertical :size="16" class="mb-8px">
|
<NSpace vertical :size="12" class="mb-8px">
|
||||||
<div class="mx-6px mb-10px flex-y-center justify-between">
|
<div class="mx-6px mb-8px flex-y-center justify-between">
|
||||||
<NCheckbox v-model:checked="remberMe" size="large">{{ $t('page.login.pwdLogin.rememberMe') }}</NCheckbox>
|
<NCheckbox v-model:checked="remberMe" size="large">{{ $t('page.login.pwdLogin.rememberMe') }}</NCheckbox>
|
||||||
<NA type="primary" class="text-18px" @click="toggleLoginModule('reset-pwd')">
|
<NA type="primary" class="text-18px" @click="toggleLoginModule('reset-pwd')">
|
||||||
{{ $t('page.login.pwdLogin.forgetPassword') }}
|
{{ $t('page.login.pwdLogin.forgetPassword') }}
|
||||||
@ -199,7 +199,7 @@ async function handleSocialLogin(type: Api.System.SocialSource) {
|
|||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-32px w-full text-center text-18px text-#858585">
|
<div class="mt-24px w-full text-center text-18px text-#858585">
|
||||||
您还没有账户?
|
您还没有账户?
|
||||||
<NA type="primary" class="text-18px" @click="toggleLoginModule('register')">
|
<NA type="primary" class="text-18px" @click="toggleLoginModule('register')">
|
||||||
{{ $t('page.login.common.register') }}
|
{{ $t('page.login.common.register') }}
|
||||||
@ -216,13 +216,13 @@ async function handleSocialLogin(type: Api.System.SocialSource) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: 52px;
|
height: 42px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.n-base-selection),
|
:deep(.n-base-selection),
|
||||||
:deep(.n-input) {
|
:deep(.n-input) {
|
||||||
--n-height: 52px !important;
|
--n-height: 42px !important;
|
||||||
--n-font-size: 16px !important;
|
--n-font-size: 16px !important;
|
||||||
--n-border-radius: 8px !important;
|
--n-border-radius: 8px !important;
|
||||||
}
|
}
|
||||||
@ -237,7 +237,7 @@ async function handleSocialLogin(type: Api.System.SocialSource) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.n-button) {
|
:deep(.n-button) {
|
||||||
--n-height: 52px !important;
|
--n-height: 42px !important;
|
||||||
--n-font-size: 18px !important;
|
--n-font-size: 18px !important;
|
||||||
--n-border-radius: 8px !important;
|
--n-border-radius: 8px !important;
|
||||||
}
|
}
|
||||||
|
@ -104,8 +104,8 @@ handleFetchCaptchaCode();
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="mb-12px text-24px text-black font-500 sm:text-30px dark:text-white">注册新账户</div>
|
<div class="mb-5px text-32px text-black font-600 sm:text-30px dark:text-white">注册新账户</div>
|
||||||
<div class="pb-24px text-18px text-#858585">欢迎注册!请输入您的账户信息</div>
|
<div class="pb-18px text-16px text-#858585">欢迎注册!请输入您的账户信息</div>
|
||||||
<NForm
|
<NForm
|
||||||
ref="formRef"
|
ref="formRef"
|
||||||
:model="model"
|
:model="model"
|
||||||
@ -147,14 +147,14 @@ handleFetchCaptchaCode();
|
|||||||
</NSpin>
|
</NSpin>
|
||||||
</div>
|
</div>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NSpace vertical :size="18" class="w-full pt-6px">
|
<NSpace vertical :size="18" class="w-full">
|
||||||
<NButton type="primary" size="large" block :loading="registerLoading" @click="handleSubmit">
|
<NButton type="primary" size="large" block :loading="registerLoading" @click="handleSubmit">
|
||||||
{{ $t('page.login.common.register') }}
|
{{ $t('page.login.common.register') }}
|
||||||
</NButton>
|
</NButton>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
</NForm>
|
</NForm>
|
||||||
|
|
||||||
<div class="mt-32px w-full text-center text-18px text-#858585">
|
<div class="mt-24px w-full text-center text-18px text-#858585">
|
||||||
您已有账户?
|
您已有账户?
|
||||||
<NA type="primary" class="text-18px" @click="toggleLoginModule('pwd-login')">
|
<NA type="primary" class="text-18px" @click="toggleLoginModule('pwd-login')">
|
||||||
{{ $t('common.login') }}
|
{{ $t('common.login') }}
|
||||||
@ -177,7 +177,7 @@ handleFetchCaptchaCode();
|
|||||||
|
|
||||||
:deep(.n-base-selection),
|
:deep(.n-base-selection),
|
||||||
:deep(.n-input) {
|
:deep(.n-input) {
|
||||||
--n-height: 52px !important;
|
--n-height: 42px !important;
|
||||||
--n-font-size: 16px !important;
|
--n-font-size: 16px !important;
|
||||||
--n-border-radius: 8px !important;
|
--n-border-radius: 8px !important;
|
||||||
}
|
}
|
||||||
@ -187,7 +187,7 @@ handleFetchCaptchaCode();
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.n-button) {
|
:deep(.n-button) {
|
||||||
--n-height: 52px !important;
|
--n-height: 42px !important;
|
||||||
--n-font-size: 18px !important;
|
--n-font-size: 18px !important;
|
||||||
--n-border-radius: 8px !important;
|
--n-border-radius: 8px !important;
|
||||||
}
|
}
|
||||||
|
@ -46,10 +46,10 @@ async function handleSubmit() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="mb-12px text-24px text-black font-500 sm:text-30px dark:text-white">
|
<div class="mb-5px text-32px text-black font-600 sm:text-30px dark:text-white">
|
||||||
{{ $t('page.login.resetPwd.title') }}
|
{{ $t('page.login.resetPwd.title') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="pb-24px text-18px text-#858585">请输入您的手机号,我们将发送验证码到您的手机</div>
|
<div class="pb-18px text-16px text-#858585">请输入您的手机号,我们将发送验证码到您的手机</div>
|
||||||
<NForm ref="formRef" :model="model" :rules="rules" size="large" :show-label="false" @keyup.enter="handleSubmit">
|
<NForm ref="formRef" :model="model" :rules="rules" size="large" :show-label="false" @keyup.enter="handleSubmit">
|
||||||
<NFormItem path="phone">
|
<NFormItem path="phone">
|
||||||
<NInput v-model:value="model.phone" :placeholder="$t('page.login.common.phonePlaceholder')" />
|
<NInput v-model:value="model.phone" :placeholder="$t('page.login.common.phonePlaceholder')" />
|
||||||
@ -73,7 +73,7 @@ async function handleSubmit() {
|
|||||||
:placeholder="$t('page.login.common.confirmPasswordPlaceholder')"
|
:placeholder="$t('page.login.common.confirmPasswordPlaceholder')"
|
||||||
/>
|
/>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NSpace vertical :size="18" class="w-full">
|
<NSpace vertical :size="20" class="w-full">
|
||||||
<NButton type="primary" size="large" block @click="handleSubmit">
|
<NButton type="primary" size="large" block @click="handleSubmit">
|
||||||
{{ $t('page.login.resetPwd.title') }}
|
{{ $t('page.login.resetPwd.title') }}
|
||||||
</NButton>
|
</NButton>
|
||||||
@ -88,7 +88,7 @@ async function handleSubmit() {
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
:deep(.n-base-selection),
|
:deep(.n-base-selection),
|
||||||
:deep(.n-input) {
|
:deep(.n-input) {
|
||||||
--n-height: 52px !important;
|
--n-height: 42px !important;
|
||||||
--n-font-size: 16px !important;
|
--n-font-size: 16px !important;
|
||||||
--n-border-radius: 8px !important;
|
--n-border-radius: 8px !important;
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ async function handleSubmit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.n-button) {
|
:deep(.n-button) {
|
||||||
--n-height: 52px !important;
|
--n-height: 42px !important;
|
||||||
--n-font-size: 18px !important;
|
--n-font-size: 18px !important;
|
||||||
--n-border-radius: 8px !important;
|
--n-border-radius: 8px !important;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user