feat: 更新登录注册页面和主布局样式

master
钟良源 4 months ago
parent c0f6f75e49
commit 72df46b096

@ -1,12 +1,41 @@
<template> <template>
<div class="multiple-layout"> <div class="multiple-layout">
<aside class="sidebar"> <!-- 顶部导航栏 -->
<header class="top-header">
<div class="header-left">
<div class="logo"> <div class="logo">
<el-icon :size="24"> <el-icon :size="22">
<DataAnalysis /> <DataAnalysis />
</el-icon> </el-icon>
<span>数据工厂</span> <span>数据工厂</span>
</div> </div>
<nav class="top-nav">
<router-link to="/data-factory" class="nav-link">工作台</router-link>
</nav>
</div>
<div class="header-right">
<el-dropdown @command="handleCommand">
<span class="user-dropdown">
<el-avatar :size="32" class="user-avatar">
{{ (userStore.userInfo.userFullName || userStore.userInfo.userAccount || '用户').slice(0, 1) }}
</el-avatar>
<span class="username">{{ userStore.userInfo.userFullName || userStore.userInfo.userAccount || '用户' }}</span>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="logout">
<el-icon><SwitchButton /></el-icon>
退出登录
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</header>
<div class="main-container">
<!-- 左侧菜单 -->
<aside class="sidebar">
<nav class="nav-menu"> <nav class="nav-menu">
<template v-for="item in menuList" :key="item.path"> <template v-for="item in menuList" :key="item.path">
<!-- 有子菜单 --> <!-- 有子菜单 -->
@ -16,10 +45,10 @@
:class="{ active: isActive(item.path), expanded: isExpanded(item.path) }" :class="{ active: isActive(item.path), expanded: isExpanded(item.path) }"
@click="toggleExpand(item.path)" @click="toggleExpand(item.path)"
> >
<el-icon> <el-icon class="menu-icon">
<component :is="item.icon" /> <component :is="item.icon" />
</el-icon> </el-icon>
<span>{{ item.title }}</span> <span class="menu-text">{{ item.title }}</span>
<el-icon class="arrow" :class="{ rotated: isExpanded(item.path) }"> <el-icon class="arrow" :class="{ rotated: isExpanded(item.path) }">
<ArrowDown /> <ArrowDown />
</el-icon> </el-icon>
@ -39,18 +68,22 @@
<router-link <router-link
v-else v-else
:to="item.path" :to="item.path"
class="menu-item"
:class="{ active: isActive(item.path) }" :class="{ active: isActive(item.path) }"
> >
<el-icon> <el-icon class="menu-icon">
<component :is="item.icon" /> <component :is="item.icon" />
</el-icon> </el-icon>
<span>{{ item.title }}</span> <span class="menu-text">{{ item.title }}</span>
</router-link> </router-link>
</template> </template>
</nav> </nav>
</aside> </aside>
<!-- 内容区域 -->
<div class="main-wrapper"> <div class="main-wrapper">
<header class="header"> <!-- 面包屑导航 -->
<div class="content-header">
<el-breadcrumb separator="/"> <el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/data-factory' }">数据工厂</el-breadcrumb-item> <el-breadcrumb-item :to="{ path: '/data-factory' }">数据工厂</el-breadcrumb-item>
<el-breadcrumb-item v-for="(item, index) in breadcrumbList" :key="index"> <el-breadcrumb-item v-for="(item, index) in breadcrumbList" :key="index">
@ -60,30 +93,15 @@
<span v-else>{{ item.title }}</span> <span v-else>{{ item.title }}</span>
</el-breadcrumb-item> </el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
<div class="header-actions">
<el-dropdown @command="handleCommand">
<span class="user-dropdown">
<el-icon><User /></el-icon>
<span class="username">{{ userStore.userInfo.userFullName || userStore.userInfo.userAccount || '用户' }}</span>
<el-icon class="arrow"><ArrowDown /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="logout">
<el-icon><SwitchButton /></el-icon>
退出登录
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div> </div>
</header>
<main class="main-content"> <main class="main-content">
<!-- 装饰背景 -->
<div class="decoration-bg"></div>
<router-view /> <router-view />
</main> </main>
</div> </div>
</div> </div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -101,7 +119,8 @@ import {
Tickets, Tickets,
Document, Document,
User, User,
SwitchButton SwitchButton,
Bell
} from '@element-plus/icons-vue' } from '@element-plus/icons-vue'
import { useUserStore } from '@/stores/modules/user' import { useUserStore } from '@/stores/modules/user'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
@ -208,65 +227,177 @@ const breadcrumbList = computed(() => {
<style scoped lang="scss"> <style scoped lang="scss">
.multiple-layout { .multiple-layout {
display: flex; display: flex;
flex-direction: column;
height: 100%; height: 100%;
width: 100%; width: 100%;
background: #f5f7fa;
} }
.sidebar { //
width: 220px; .top-header {
background: linear-gradient(180deg, #1e3a5f 0%, #0d2137 100%); height: 56px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
flex-shrink: 0; flex-shrink: 0;
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
position: relative;
z-index: 100;
}
.header-left {
display: flex; display: flex;
flex-direction: column; align-items: center;
gap: 32px;
} }
.logo { .logo {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
padding: 20px;
color: #fff; color: #fff;
font-size: 18px; font-size: 18px;
font-weight: 600; font-weight: 600;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
.el-icon { .el-icon {
color: #409eff; color: #fff;
} }
} }
.nav-menu { .top-nav {
display: flex;
align-items: center;
gap: 8px;
.nav-link {
color: rgba(255, 255, 255, 0.85);
text-decoration: none;
padding: 6px 16px;
border-radius: 6px;
font-size: 14px;
transition: all 0.2s;
&:hover,
&.router-link-active {
color: #fff;
background: rgba(255, 255, 255, 0.15);
}
}
}
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.header-icon {
color: rgba(255, 255, 255, 0.85);
font-size: 20px;
cursor: pointer;
padding: 8px;
border-radius: 8px;
transition: all 0.2s;
&:hover {
color: #fff;
background: rgba(255, 255, 255, 0.15);
}
}
.user-dropdown {
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
padding: 4px 8px;
border-radius: 8px;
transition: all 0.2s;
&:hover {
background: rgba(255, 255, 255, 0.15);
}
.user-avatar {
background: rgba(255, 255, 255, 0.25);
color: #fff;
font-size: 14px;
font-weight: 500;
}
.username {
color: #fff;
font-size: 14px;
max-width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
//
.main-container {
display: flex; display: flex;
flex-direction: column;
padding: 12px 0;
flex: 1; flex: 1;
overflow: hidden;
}
//
.sidebar {
width: 200px;
background: #fff;
flex-shrink: 0;
display: flex;
flex-direction: column;
border-right: 1px solid #e8ecf0;
overflow-y: auto; overflow-y: auto;
}
> a { .nav-menu {
display: flex;
flex-direction: column;
padding: 12px 8px;
.menu-item {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 12px;
color: rgba(255, 255, 255, 0.7); color: #5a6474;
text-decoration: none; text-decoration: none;
padding: 14px 24px; padding: 12px 16px;
font-size: 14px; font-size: 14px;
transition: all 0.3s; transition: all 0.2s;
margin: 2px 12px;
border-radius: 8px; border-radius: 8px;
margin-bottom: 4px;
.el-icon { .menu-icon {
font-size: 18px; font-size: 18px;
color: #8b95a5;
}
.menu-text {
flex: 1;
} }
&:hover { &:hover {
color: #fff; color: #667eea;
background: rgba(64, 158, 255, 0.15); background: #f0f3ff;
.menu-icon {
color: #667eea;
}
} }
&.active { &.active {
color: #fff; color: #667eea;
background: linear-gradient(90deg, #409eff 0%, #2a7dc9 100%); background: linear-gradient(135deg, #f0f3ff 0%, #e8ecff 100%);
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4); font-weight: 500;
.menu-icon {
color: #667eea;
}
} }
} }
} }
@ -275,22 +406,27 @@ const breadcrumbList = computed(() => {
.menu-item.parent { .menu-item.parent {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 12px;
color: rgba(255, 255, 255, 0.7); color: #5a6474;
padding: 14px 24px; padding: 12px 16px;
font-size: 14px; font-size: 14px;
transition: all 0.3s; transition: all 0.2s;
margin: 2px 12px;
border-radius: 8px; border-radius: 8px;
margin-bottom: 4px;
cursor: pointer; cursor: pointer;
.el-icon { .menu-icon {
font-size: 18px; font-size: 18px;
color: #8b95a5;
}
.menu-text {
flex: 1;
} }
.arrow { .arrow {
margin-left: auto;
font-size: 12px; font-size: 12px;
color: #8b95a5;
transition: transform 0.3s; transition: transform 0.3s;
&.rotated { &.rotated {
@ -299,12 +435,22 @@ const breadcrumbList = computed(() => {
} }
&:hover { &:hover {
color: #fff; color: #667eea;
background: rgba(64, 158, 255, 0.15); background: #f0f3ff;
.menu-icon,
.arrow {
color: #667eea;
}
} }
&.active { &.active {
color: #fff; color: #667eea;
font-weight: 500;
.menu-icon {
color: #667eea;
}
} }
} }
@ -320,102 +466,84 @@ const breadcrumbList = computed(() => {
a { a {
display: flex; display: flex;
align-items: center; align-items: center;
color: rgba(255, 255, 255, 0.6); color: #6b7785;
text-decoration: none; text-decoration: none;
padding: 10px 24px 10px 52px; padding: 10px 16px 10px 46px;
font-size: 13px; font-size: 13px;
transition: all 0.2s; transition: all 0.2s;
margin: 1px 12px;
border-radius: 6px; border-radius: 6px;
margin: 2px 8px;
&:hover { &:hover {
color: #fff; color: #667eea;
background: rgba(64, 158, 255, 0.1); background: #f5f7ff;
} }
&.active { &.active {
color: #409eff; color: #667eea;
background: rgba(64, 158, 255, 0.2); background: #f0f3ff;
font-weight: 500;
} }
} }
} }
} }
//
.main-wrapper { .main-wrapper {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
background: #f0f2f5; background: linear-gradient(180deg, #eef2f9 0%, #e8edf5 100%);
} }
.header { .content-header {
background: #fff;
padding: 16px 24px; padding: 16px 24px;
border-bottom: 1px solid #e8e8e8;
flex-shrink: 0; flex-shrink: 0;
display: flex;
justify-content: space-between;
align-items: center;
:deep(.el-breadcrumb) { :deep(.el-breadcrumb) {
font-size: 14px; font-size: 13px;
.el-breadcrumb__item { .el-breadcrumb__item {
.el-breadcrumb__inner { .el-breadcrumb__inner {
color: #666; color: #8b95a5;
a { a {
color: #666; color: #8b95a5;
font-weight: normal; font-weight: normal;
&:hover { &:hover {
color: #409eff; color: #667eea;
} }
} }
} }
&:last-child .el-breadcrumb__inner { &:last-child .el-breadcrumb__inner {
color: #333; color: #5a6474;
font-weight: 500; font-weight: 500;
} }
} }
} }
} }
.header-actions {
.user-dropdown {
display: flex;
align-items: center;
gap: 6px;
cursor: pointer;
color: #666;
font-size: 14px;
padding: 6px 12px;
border-radius: 6px;
transition: all 0.2s;
&:hover {
background: #f5f5f5;
color: #409eff;
}
.username {
max-width: 120px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.arrow {
font-size: 12px;
}
}
}
.main-content { .main-content {
flex: 1; flex: 1;
overflow: auto; overflow: auto;
padding: 20px; padding: 0 24px 24px;
position: relative;
}
//
.decoration-bg {
position: absolute;
top: 0;
right: 0;
width: 400px;
height: 300px;
background:
radial-gradient(circle at 80% 20%, rgba(102, 126, 234, 0.08) 0%, transparent 50%),
radial-gradient(circle at 90% 80%, rgba(118, 75, 162, 0.06) 0%, transparent 40%);
pointer-events: none;
z-index: 0;
} }
</style> </style>

@ -1,9 +1,44 @@
<template> <template>
<div class="login-container"> <div class="login-container">
<!-- 装饰背景 -->
<div class="decoration">
<div class="circle circle-1"></div>
<div class="circle circle-2"></div>
<div class="circle circle-3"></div>
</div>
<div class="login-wrapper"> <div class="login-wrapper">
<!-- 左侧品牌区域 -->
<div class="brand-section">
<div class="brand-content">
<div class="brand-icon">
<el-icon :size="48"><DataAnalysis /></el-icon>
</div>
<h1 class="brand-title">数据工厂</h1>
<p class="brand-desc">智能数据处理与分析平台</p>
<div class="brand-features">
<div class="feature-item">
<el-icon><Check /></el-icon>
<span>数据连接与集成</span>
</div>
<div class="feature-item">
<el-icon><Check /></el-icon>
<span>流程自动化处理</span>
</div>
<div class="feature-item">
<el-icon><Check /></el-icon>
<span>智能数据标注</span>
</div>
</div>
</div>
</div>
<!-- 右侧登录表单 -->
<div class="login-section">
<div class="login-card"> <div class="login-card">
<div class="login-header"> <div class="login-header">
<h2 class="login-title">欢迎登录</h2> <h2 class="login-title">欢迎回来</h2>
<p class="login-subtitle">请登录您的账号</p>
</div> </div>
<el-form <el-form
ref="loginFormRef" ref="loginFormRef"
@ -32,7 +67,9 @@
/> />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<div class="form-options">
<el-checkbox v-model="rememberPassword"></el-checkbox> <el-checkbox v-model="rememberPassword"></el-checkbox>
</div>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button <el-button
@ -46,20 +83,21 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<div class="register-link"> <div class="register-link">
没有账号<router-link to="/register">立即注册</router-link> 没有账号<router-link to="/register">立即注册</router-link>
</div> </div>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
</div> </div>
</div> </div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {User, Lock} from '@element-plus/icons-vue' import { User, Lock, DataAnalysis, Check } from '@element-plus/icons-vue'
import {ElMessage, FormInstance, FormRules} from 'element-plus' import { ElMessage, FormInstance, FormRules } from 'element-plus'
import {useUserStore} from '@/stores/modules/user' import { useUserStore } from '@/stores/modules/user'
import {useRouter, useRoute} from 'vue-router' import { useRouter, useRoute } from 'vue-router'
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
@ -76,11 +114,11 @@ const loginForm = reactive({
const loginRules: FormRules = { const loginRules: FormRules = {
username: [ username: [
{required: true, message: '请输入用户名', trigger: 'blur'}, { required: true, message: '请输入用户名', trigger: 'blur' },
{min: 1, max: 50, message: '用户名长度不超过50字符', trigger: 'blur'} { min: 1, max: 50, message: '用户名长度不超过50字符', trigger: 'blur' }
], ],
password: [ password: [
{required: true, message: '请输入密码', trigger: 'blur'} { required: true, message: '请输入密码', trigger: 'blur' }
] ]
} }
@ -89,7 +127,7 @@ onMounted(() => {
const savedCredentials = localStorage.getItem('login-credentials') const savedCredentials = localStorage.getItem('login-credentials')
if (savedCredentials) { if (savedCredentials) {
try { try {
const {username, password} = JSON.parse(atob(savedCredentials)) const { username, password } = JSON.parse(atob(savedCredentials))
loginForm.username = username || '' loginForm.username = username || ''
loginForm.password = password || '' loginForm.password = password || ''
} catch (e) { } catch (e) {
@ -115,7 +153,7 @@ const handleLogin = async () => {
if (rememberPassword.value) { if (rememberPassword.value) {
localStorage.setItem( localStorage.setItem(
'login-credentials', 'login-credentials',
btoa(JSON.stringify({username: loginForm.username, password: loginForm.password})) btoa(JSON.stringify({ username: loginForm.username, password: loginForm.password }))
) )
} else { } else {
localStorage.removeItem('login-credentials') localStorage.removeItem('login-credentials')
@ -138,66 +176,270 @@ const handleLogin = async () => {
.login-container { .login-container {
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
background: linear-gradient(135deg, #1e3a5f 0%, #0d2137 100%); background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
position: relative;
overflow: hidden;
}
//
.decoration {
position: absolute;
inset: 0;
pointer-events: none;
overflow: hidden;
.circle {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
}
.circle-1 {
width: 600px;
height: 600px;
top: -200px;
right: -100px;
}
.circle-2 {
width: 400px;
height: 400px;
bottom: -100px;
left: -100px;
}
.circle-3 {
width: 200px;
height: 200px;
top: 50%;
left: 20%;
background: rgba(255, 255, 255, 0.05);
}
} }
.login-wrapper { .login-wrapper {
width: 100%; display: flex;
max-width: 400px; width: 900px;
padding: 20px; max-width: 95%;
background: #fff;
border-radius: 24px;
overflow: hidden;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
position: relative;
z-index: 1;
}
//
.brand-section {
flex: 1;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 60px 40px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
inset: 0;
background:
radial-gradient(circle at 20% 80%, rgba(255, 255, 255, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(255, 255, 255, 0.08) 0%, transparent 50%);
}
}
.brand-content {
position: relative;
z-index: 1;
text-align: center;
color: #fff;
}
.brand-icon {
width: 80px;
height: 80px;
background: rgba(255, 255, 255, 0.2);
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 24px;
backdrop-filter: blur(10px);
}
.brand-title {
font-size: 32px;
font-weight: 700;
margin: 0 0 12px;
}
.brand-desc {
font-size: 16px;
opacity: 0.9;
margin: 0 0 40px;
}
.brand-features {
text-align: left;
display: inline-block;
.feature-item {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
font-size: 14px;
opacity: 0.9;
.el-icon {
width: 20px;
height: 20px;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
}
}
//
.login-section {
flex: 1;
padding: 60px 50px;
display: flex;
align-items: center;
justify-content: center;
} }
.login-card { .login-card {
background: #fff; width: 100%;
border-radius: 12px; max-width: 320px;
padding: 40px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
} }
.login-header { .login-header {
text-align: center; margin-bottom: 32px;
margin-bottom: 30px;
} }
.login-title { .login-title {
font-size: 24px; font-size: 28px;
font-weight: 600; font-weight: 700;
color: #333; color: #1a1a2e;
margin: 0 0 8px;
}
.login-subtitle {
font-size: 14px;
color: #8b95a5;
margin: 0; margin: 0;
padding-bottom: 10px;
border-bottom: 3px solid #1e3a5f;
display: inline-block;
} }
.login-form { .login-form {
.el-form-item { :deep(.el-form-item) {
margin-bottom: 20px; margin-bottom: 20px;
} }
:deep(.el-input__wrapper) {
border-radius: 10px;
padding: 4px 12px;
box-shadow: 0 0 0 1px #e8ecf0;
transition: all 0.2s;
&:hover {
box-shadow: 0 0 0 1px #667eea;
}
&.is-focus {
box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2);
}
}
:deep(.el-input__inner) {
height: 44px;
}
}
.form-options {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
:deep(.el-checkbox__label) {
color: #6b7785;
font-size: 13px;
}
} }
.login-btn { .login-btn {
width: 100%; width: 100%;
height: 44px; height: 48px;
font-size: 16px; font-size: 16px;
border-radius: 8px; font-weight: 500;
border-radius: 10px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
transition: all 0.3s;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
}
&:active {
transform: translateY(0);
}
} }
.register-link { .register-link {
width: 100%; width: 100%;
text-align: center; text-align: center;
color: #666; color: #8b95a5;
font-size: 14px;
a { a {
color: #1e3a5f; color: #667eea;
text-decoration: none; text-decoration: none;
font-weight: 500; font-weight: 500;
transition: color 0.2s;
&:hover { &:hover {
text-decoration: underline; color: #764ba2;
}
} }
}
//
@media (max-width: 768px) {
.login-wrapper {
flex-direction: column;
max-width: 400px;
}
.brand-section {
padding: 40px 30px;
.brand-features {
display: none;
}
}
.brand-title {
font-size: 24px;
}
.brand-desc {
margin-bottom: 0;
}
.login-section {
padding: 40px 30px;
} }
} }
</style> </style>

@ -1,9 +1,44 @@
<template> <template>
<div class="register-container"> <div class="register-container">
<!-- 装饰背景 -->
<div class="decoration">
<div class="circle circle-1"></div>
<div class="circle circle-2"></div>
<div class="circle circle-3"></div>
</div>
<div class="register-wrapper"> <div class="register-wrapper">
<!-- 左侧品牌区域 -->
<div class="brand-section">
<div class="brand-content">
<div class="brand-icon">
<el-icon :size="48"><DataAnalysis /></el-icon>
</div>
<h1 class="brand-title">数据工厂</h1>
<p class="brand-desc">智能数据处理与分析平台</p>
<div class="brand-features">
<div class="feature-item">
<el-icon><Check /></el-icon>
<span>数据连接与集成</span>
</div>
<div class="feature-item">
<el-icon><Check /></el-icon>
<span>流程自动化处理</span>
</div>
<div class="feature-item">
<el-icon><Check /></el-icon>
<span>智能数据标注</span>
</div>
</div>
</div>
</div>
<!-- 右侧注册表单 -->
<div class="register-section">
<div class="register-card"> <div class="register-card">
<div class="register-header"> <div class="register-header">
<h2 class="register-title">用户注册</h2> <h2 class="register-title">创建账号</h2>
<p class="register-subtitle">注册以开始使用数据工厂</p>
</div> </div>
<el-form <el-form
ref="registerFormRef" ref="registerFormRef"
@ -60,10 +95,11 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { User, Lock } from '@element-plus/icons-vue' import { User, Lock, DataAnalysis, Check } from '@element-plus/icons-vue'
import { ElMessage, FormInstance, FormRules } from 'element-plus' import { ElMessage, FormInstance, FormRules } from 'element-plus'
import { useUserStore } from '@/stores/modules/user' import { useUserStore } from '@/stores/modules/user'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
@ -130,66 +166,258 @@ const handleRegister = async () => {
.register-container { .register-container {
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
background: linear-gradient(135deg, #1e3a5f 0%, #0d2137 100%); background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
position: relative;
overflow: hidden;
}
//
.decoration {
position: absolute;
inset: 0;
pointer-events: none;
overflow: hidden;
.circle {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
}
.circle-1 {
width: 600px;
height: 600px;
top: -200px;
right: -100px;
}
.circle-2 {
width: 400px;
height: 400px;
bottom: -100px;
left: -100px;
}
.circle-3 {
width: 200px;
height: 200px;
top: 50%;
left: 20%;
background: rgba(255, 255, 255, 0.05);
}
} }
.register-wrapper { .register-wrapper {
width: 100%; display: flex;
max-width: 400px; width: 900px;
padding: 20px; max-width: 95%;
background: #fff;
border-radius: 24px;
overflow: hidden;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
position: relative;
z-index: 1;
}
//
.brand-section {
flex: 1;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 60px 40px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
inset: 0;
background:
radial-gradient(circle at 20% 80%, rgba(255, 255, 255, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(255, 255, 255, 0.08) 0%, transparent 50%);
}
}
.brand-content {
position: relative;
z-index: 1;
text-align: center;
color: #fff;
}
.brand-icon {
width: 80px;
height: 80px;
background: rgba(255, 255, 255, 0.2);
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 24px;
backdrop-filter: blur(10px);
}
.brand-title {
font-size: 32px;
font-weight: 700;
margin: 0 0 12px;
}
.brand-desc {
font-size: 16px;
opacity: 0.9;
margin: 0 0 40px;
}
.brand-features {
text-align: left;
display: inline-block;
.feature-item {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
font-size: 14px;
opacity: 0.9;
.el-icon {
width: 20px;
height: 20px;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
}
}
//
.register-section {
flex: 1;
padding: 60px 50px;
display: flex;
align-items: center;
justify-content: center;
} }
.register-card { .register-card {
background: #fff; width: 100%;
border-radius: 12px; max-width: 320px;
padding: 40px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
} }
.register-header { .register-header {
text-align: center; margin-bottom: 32px;
margin-bottom: 30px;
} }
.register-title { .register-title {
font-size: 24px; font-size: 28px;
font-weight: 600; font-weight: 700;
color: #333; color: #1a1a2e;
margin: 0 0 8px;
}
.register-subtitle {
font-size: 14px;
color: #8b95a5;
margin: 0; margin: 0;
padding-bottom: 10px;
border-bottom: 3px solid #1e3a5f;
display: inline-block;
} }
.register-form { .register-form {
.el-form-item { :deep(.el-form-item) {
margin-bottom: 20px; margin-bottom: 20px;
} }
:deep(.el-input__wrapper) {
border-radius: 10px;
padding: 4px 12px;
box-shadow: 0 0 0 1px #e8ecf0;
transition: all 0.2s;
&:hover {
box-shadow: 0 0 0 1px #667eea;
}
&.is-focus {
box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2);
}
}
:deep(.el-input__inner) {
height: 44px;
}
} }
.register-btn { .register-btn {
width: 100%; width: 100%;
height: 44px; height: 48px;
font-size: 16px; font-size: 16px;
border-radius: 8px; font-weight: 500;
border-radius: 10px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
transition: all 0.3s;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
}
&:active {
transform: translateY(0);
}
} }
.login-link { .login-link {
width: 100%; width: 100%;
text-align: center; text-align: center;
color: #666; color: #8b95a5;
font-size: 14px;
a { a {
color: #1e3a5f; color: #667eea;
text-decoration: none; text-decoration: none;
font-weight: 500; font-weight: 500;
transition: color 0.2s;
&:hover { &:hover {
text-decoration: underline; color: #764ba2;
} }
} }
} }
//
@media (max-width: 768px) {
.register-wrapper {
flex-direction: column;
max-width: 400px;
}
.brand-section {
padding: 40px 30px;
.brand-features {
display: none;
}
}
.brand-title {
font-size: 24px;
}
.brand-desc {
margin-bottom: 0;
}
.register-section {
padding: 40px 30px;
}
}
</style> </style>

Loading…
Cancel
Save