Compare commits

...

10 Commits

Author SHA1 Message Date
bakaECC
c9e8dd286a 配置Vite监听所有接口 2025-12-10 18:06:34 +08:00
bakaECC
d242217686 优化登录页样式布局和动画效果 2025-12-10 18:06:31 +08:00
bakaECC
f14ebb9f0c 优化滚动条显示逻辑与样式限制 2025-12-10 18:06:25 +08:00
bakaECC
a6d5c25e1c 将代理目标地址修改为局域网IP 2025-12-10 16:28:18 +08:00
bakaECC
906b5f37a7 优化登录页面布局和动画效果 2025-12-10 16:28:16 +08:00
bakaECC
2fe89ff491 重用重构的聊天布局 2025-12-10 16:28:14 +08:00
bakaECC
2916e2c667 注释更改请求基础URL 2025-12-10 16:28:12 +08:00
bakaECC
0d48c90334 引入设计系统样式 2025-12-10 16:28:10 +08:00
bakaECC
f4ab164585 添加动态Blob背景效果 2025-12-10 16:28:08 +08:00
bakaECC
1a727325d5 优化顶部栏样式与视觉效果 2025-12-10 16:28:06 +08:00
8 changed files with 613 additions and 78 deletions

View File

@ -63,7 +63,7 @@
<div class="flex-1 flex flex-col min-h-0 px-4 pt-4 pb-4 relative z-10"> <div class="flex-1 flex flex-col min-h-0 px-4 pt-4 pb-4 relative z-10">
<div class="flex items-end justify-between mb-2"> <div class="flex items-end justify-between mb-2">
<div <div
class="flex items-end gap-1 overflow-x-auto scrollbar-custom flex-1" class="flex items-end gap-1 overflow-x-auto overflow-y-hidden scrollbar-custom flex-1"
> >
<button <button
class="px-4 py-2 text-xs font-medium bg-white/30 text-foreground rounded-t-2xl shadow-sm -mb-[1px]" class="px-4 py-2 text-xs font-medium bg-white/30 text-foreground rounded-t-2xl shadow-sm -mb-[1px]"
@ -77,10 +77,10 @@
</button> </button>
</div> </div>
<button <button
class="w-6 h-6 rounded-md bg-white/40 border border-white/40 flex items-center justify-center text-xs" class="h-9 px-4 rounded-full bg-gradient-to-r from-blue-500 to-blue-400 border border-white/60 shadow-lg text-white flex items-center justify-center text-[11px] font-semibold hover:shadow-xl hover:scale-105 transition-all"
@click="newConversation" @click="newConversation"
> >
+ 新会话
</button> </button>
</div> </div>
@ -386,7 +386,7 @@
? '输入关键词搜索图片(实时搜索)...' ? '输入关键词搜索图片(实时搜索)...'
: '请输入工程参数、需求或问题...' : '请输入工程参数、需求或问题...'
" "
class="composer-textarea" :class="['composer-textarea', { 'show-scrollbar': showTextareaScrollbar }]"
@keydown="handleKeydown" @keydown="handleKeydown"
:disabled="loading" :disabled="loading"
/> />
@ -622,7 +622,7 @@
<div v-if="msg.isSearchBox" class="search-card"> <div v-if="msg.isSearchBox" class="search-card">
<div class="search-head"> <div class="search-head">
<div class="search-head__left"> <div class="search-head__left">
<span class="mode-pill">🔍 文档检索模式</span> <span class="mode-pill">文档检索模式</span>
<div> <div>
<p class="head-title">工程档案 · 精准检索</p> <p class="head-title">工程档案 · 精准检索</p>
<p class="head-desc"> <p class="head-desc">
@ -1207,7 +1207,7 @@
? '输入关键词搜索图片(实时搜索)...' ? '输入关键词搜索图片(实时搜索)...'
: '请输入工程参数、需求或问题...' : '请输入工程参数、需求或问题...'
" "
class="composer-textarea" :class="['composer-textarea', { 'show-scrollbar': showTextareaScrollbar }]"
@keydown="handleKeydown" @keydown="handleKeydown"
:disabled="loading" :disabled="loading"
/> />
@ -1854,6 +1854,11 @@ const isSingleLine = computed(() => {
return !inputText.value.includes('\n') && inputText.value.length < 50 return !inputText.value.includes('\n') && inputText.value.length < 50
}) })
const showTextareaScrollbar = computed(() => {
const lines = inputText.value.split(/\r?\n/)
return lines.length > 2
})
const guidePrompts = [ const guidePrompts = [
{ {
id: 'knowledge-base', id: 'knowledge-base',
@ -3518,12 +3523,15 @@ function terminateProcess(msg, msgIndex) {
justify-content: space-between; justify-content: space-between;
gap: 16px; gap: 16px;
margin-bottom: 16px; margin-bottom: 16px;
flex-wrap: nowrap;
white-space: nowrap;
} }
.search-head__left { .search-head__left {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12px; gap: 12px;
flex-wrap: nowrap;
} }
.mode-pill { .mode-pill {
@ -3544,12 +3552,14 @@ function terminateProcess(msg, msgIndex) {
font-size: 16px; font-size: 16px;
color: hsl(var(--foreground)); color: hsl(var(--foreground));
line-height: 1.2; line-height: 1.2;
white-space: nowrap;
} }
.head-desc { .head-desc {
margin-top: 2px; margin-top: 2px;
font-size: 12px; font-size: 12px;
color: hsl(var(--muted-foreground)); color: hsl(var(--muted-foreground));
white-space: nowrap;
} }
.head-stats { .head-stats {
@ -4386,6 +4396,29 @@ function terminateProcess(msg, msgIndex) {
padding: 0; padding: 0;
line-height: 1.6; line-height: 1.6;
text-align: left; text-align: left;
overflow-y: hidden;
scrollbar-width: none;
-ms-overflow-style: none;
}
.composer-textarea :deep(.el-textarea__inner::-webkit-scrollbar) {
width: 0;
height: 0;
}
.composer-textarea.show-scrollbar :deep(.el-textarea__inner) {
overflow-y: auto;
scrollbar-width: thin;
}
.composer-textarea.show-scrollbar :deep(.el-textarea__inner::-webkit-scrollbar) {
width: 6px;
height: 6px;
}
.composer-textarea.show-scrollbar :deep(.el-textarea__inner::-webkit-scrollbar-thumb) {
background: hsla(220, 20%, 60%, 0.3);
border-radius: 999px;
} }
.composer-textarea :deep(.el-textarea__inner):focus { .composer-textarea :deep(.el-textarea__inner):focus {

View File

@ -114,23 +114,47 @@ export default defineComponent({
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.header { .header {
position: relative;
height: 48px; height: 48px;
border-bottom: 1px solid #e0e4ef; border-bottom: 1px solid rgba(255, 255, 255, 0.2);
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
background: transparent;
//
&::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.5), transparent);
pointer-events: none;
}
&.no-border { &.no-border {
border: none; border: none;
&::after {
display: none;
} }
}
.navigation { .navigation {
display: flex; display: flex;
align-items: center; align-items: center;
overflow: hidden; overflow: hidden;
padding: 0 16px;
} }
.action { .action {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0 16px;
gap: 8px;
} }
} }
.mobile { .mobile {
padding-right: 0; padding-right: 0;
::v-deep(.logo) { ::v-deep(.logo) {
@ -141,10 +165,12 @@ export default defineComponent({
display: none; display: none;
} }
} }
.show-title { .show-title {
::v-deep(.title) { ::v-deep(.title) {
display: block; display: block;
color: #333; color: hsl(var(--foreground));
font-weight: 600;
} }
} }
</style> </style>

View File

@ -36,6 +36,13 @@
<template> <template>
<div class="wrapper" :class="{ fluid: isFluid }"> <div class="wrapper" :class="{ fluid: isFluid }">
<!-- 动态 Blob 背景 -->
<div class="blob-container">
<div class="blob blob-1"></div>
<div class="blob blob-2"></div>
<div class="blob blob-3"></div>
</div>
<sidebar v-if="isMenusShow && !isHorizontalMenu" /> <sidebar v-if="isMenusShow && !isHorizontalMenu" />
<div class="right" :class="{ flex: isTopbarFixed }"> <div class="right" :class="{ flex: isTopbarFixed }">
<div class="top"> <div class="top">
@ -106,30 +113,94 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
.wrapper { .wrapper {
position: relative;
display: flex; display: flex;
margin: 0 auto; margin: 0 auto;
width: 1440px; width: 1440px;
height: 100%; height: 100vh;
overflow: hidden;
background: hsl(var(--background));
&.fluid { &.fluid {
width: 100%; width: 100%;
} }
// Blob
.blob-container {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
z-index: 0;
}
.blob {
position: absolute;
border-radius: 50%;
filter: blur(100px);
opacity: 0.4;
pointer-events: none;
}
.blob-1 {
width: 800px;
height: 800px;
background: linear-gradient(135deg, rgba(56, 189, 248, 0.25), rgba(34, 211, 238, 0.2));
top: -300px;
right: -300px;
animation: blob-float 20s ease-in-out infinite;
}
.blob-2 {
width: 700px;
height: 700px;
background: linear-gradient(135deg, rgba(139, 92, 246, 0.2), rgba(168, 85, 247, 0.25));
bottom: -250px;
left: -250px;
animation: blob-float-2 25s ease-in-out infinite;
}
.blob-3 {
width: 600px;
height: 600px;
background: linear-gradient(135deg, rgba(59, 130, 246, 0.22), rgba(96, 165, 250, 0.18));
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
animation: blob-float-3 30s ease-in-out infinite;
}
.right { .right {
position: relative;
z-index: 1;
flex: 1; flex: 1;
overflow: auto; overflow: auto;
background: transparent;
&.flex { &.flex {
overflow: hidden; overflow: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.top { .top {
background: #fff; position: relative;
z-index: 10;
background: rgba(255, 255, 255, 0.4);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-bottom: 1px solid rgba(255, 255, 255, 0.3);
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.03);
} }
.main { .main {
position: relative;
z-index: 1;
flex: 1; flex: 1;
background: #f5f5f5; background: transparent;
padding: 16px; padding: 16px;
overflow: auto; overflow: auto;
&.pt0 { &.pt0 {
padding-top: 0; padding-top: 0;
} }

View File

@ -39,6 +39,9 @@ import App from './App.vue'
const app = createApp(App) const app = createApp(App)
// 引入设计系统Tailwind CSS + 设计变量)
import './assets/style/design-system.css'
// 引入element-plus // 引入element-plus
import ElementPlus from 'element-plus' import ElementPlus from 'element-plus'
import './assets/style/element-variables.scss' import './assets/style/element-variables.scss'

View File

@ -36,7 +36,7 @@ import { useApp } from '@/pinia/modules/app'
const service = axios.create({ const service = axios.create({
baseURL: '', baseURL: '',
// baseURL: 'http://localhost:8501', // baseURL: 'http://192.168.0.240:8501',
timeout: 10000, timeout: 10000,
withCredentials: true, withCredentials: true,
}) })

View File

@ -1,6 +1,8 @@
<!-- first.vue -->
<template> <template>
<el-radio-button label="chat_view" size="default"> <!-- 完整聊天页面直接复用已重构的 chat_layout -->
知识库 <ChatLayout />
</el-radio-button>
</template> </template>
<script setup>
import ChatLayout from '@/layout/chat_layout.vue'
</script>

View File

@ -11,9 +11,24 @@
--> -->
<template> <template>
<div class="login"> <div class="login">
<!-- 动态 Blob 背景 -->
<div class="blob-container">
<div class="blob blob-1"></div>
<div class="blob blob-2"></div>
<div class="blob blob-3"></div>
</div>
<div class="shell">
<el-form class="form" :model="model" :rules="rules" ref="loginForm"> <el-form class="form" :model="model" :rules="rules" ref="loginForm">
<!-- <h1 class="title">Vue3 Element Admin</h1>--> <div class="form-meta">
<h1 class="title">凌空天行 AI大模型 应用系统</h1> <div>
<p class="eyebrow">LOGIN</p>
<h2 class="title">登录工作台</h2>
<p class="title-desc">使用企业账户或SSO登录</p>
</div>
<!-- <div class="tag gradient">凌能空间</div> -->
</div>
<el-form-item prop="userName"> <el-form-item prop="userName">
<el-input <el-input
class="text" class="text"
@ -34,7 +49,6 @@
/> />
</el-form-item> </el-form-item>
<!-- 页面结构 -->
<el-form-item prop="captcha"> <el-form-item prop="captcha">
<div class="captcha"> <div class="captcha">
<el-input <el-input
@ -42,7 +56,7 @@
v-model="model.captcha" v-model="model.captcha"
prefix-icon="Picture" prefix-icon="Picture"
placeholder="请输入验证码" placeholder="请输入验证码"
></el-input> />
<img :src="captchaSrc" @click="refreshCaptcha" /> <img :src="captchaSrc" @click="refreshCaptcha" />
</div> </div>
</el-form-item> </el-form-item>
@ -58,8 +72,22 @@
{{ btnText }} {{ btnText }}
</el-button> </el-button>
</el-form-item> </el-form-item>
<div class="divider">
<span></span>
</div>
<el-button
class="btn-sso"
size="large"
plain
@click="handleSsoLogin"
>
企业SSO 一键登录
</el-button>
</el-form> </el-form>
</div> </div>
</div>
<div class="change-lang"> <div class="change-lang">
<change-lang /> <change-lang />
</div> </div>
@ -140,6 +168,13 @@ export default defineComponent({
state.loading ? ctx.$t('login.logining') : ctx.$t('login.login') state.loading ? ctx.$t('login.logining') : ctx.$t('login.login')
), ),
loginForm: ref(null), loginForm: ref(null),
ssoEndpoint: import.meta.env.VITE_SSO_URL || '/sso/login',
handleSsoLogin: () => {
const redirect = route.query.redirect || window.location.href
window.location.href = `${state.ssoEndpoint}?redirect=${encodeURIComponent(
redirect
)}`
},
submit: () => { submit: () => {
if (state.loading) { if (state.loading) {
return return
@ -188,32 +223,216 @@ export default defineComponent({
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-bottom: 10px; margin-bottom: 10px;
gap: 12px;
} }
.captcha img { .captcha img {
cursor: pointer; cursor: pointer;
margin-left: 20px; border-radius: 8px;
transition: transform 0.3s ease;
&:hover {
transform: scale(1.05);
}
} }
// end // end
.login { .login {
transition: transform 1s; position: relative;
transform: scale(1);
width: 100%; width: 100%;
height: 100%; min-height: 100vh;
overflow: hidden; overflow: hidden;
background: #2d3a4b; padding: 72px 28px;
.form { display: flex;
align-items: center;
background: radial-gradient(circle at 18% 22%, rgba(104, 173, 255, 0.2), transparent 30%),
radial-gradient(circle at 80% 14%, rgba(139, 92, 246, 0.12), transparent 26%),
radial-gradient(circle at 28% 82%, rgba(94, 234, 212, 0.12), transparent 24%),
linear-gradient(145deg, #f5f7fb 0%, #edf0f6 45%, #e7ebf2 100%);
&::before,
&::after {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
mix-blend-mode: soft-light;
background: repeating-linear-gradient(
90deg,
rgba(255, 255, 255, 0.04) 0,
rgba(255, 255, 255, 0.04) 1px,
transparent 1px,
transparent 22px
),
repeating-linear-gradient(
0deg,
rgba(255, 255, 255, 0.04) 0,
rgba(255, 255, 255, 0.04) 1px,
transparent 1px,
transparent 22px
);
}
&::after {
background: radial-gradient(circle at 40% 30%, rgba(255, 255, 255, 0.08), transparent 35%),
radial-gradient(circle at 65% 70%, rgba(255, 255, 255, 0.08), transparent 30%);
filter: blur(36px);
}
// Blob
.blob-container {
position: absolute;
inset: -12%;
overflow: hidden;
pointer-events: none;
z-index: 0;
}
.blob {
position: absolute;
border-radius: 50%;
filter: blur(100px);
opacity: 0.46;
pointer-events: none;
mix-blend-mode: screen;
}
.blob-1 {
width: 520px; width: 520px;
max-width: 100%; height: 520px;
padding: 0 24px; background: linear-gradient(135deg, rgba(93, 156, 255, 0.32), rgba(141, 198, 255, 0.24));
top: -140px;
right: -160px;
animation: blob-float 18s ease-in-out infinite;
}
.blob-2 {
width: 500px;
height: 500px;
background: linear-gradient(135deg, rgba(126, 211, 180, 0.26), rgba(121, 189, 255, 0.22));
bottom: -140px;
left: -120px;
animation: blob-float-2 22s ease-in-out infinite;
}
.blob-3 {
width: 420px;
height: 420px;
background: linear-gradient(135deg, rgba(255, 214, 165, 0.28), rgba(161, 196, 253, 0.22));
top: 48%;
left: 50%;
transform: translate(-50%, -50%);
animation: blob-float-3 26s ease-in-out infinite;
}
.shell {
position: relative;
z-index: 10;
width: min(520px, 100%);
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
}
.brand-chip {
display: inline-flex;
align-items: center;
padding: 6px 12px;
border-radius: 999px;
font-size: 12px;
letter-spacing: 0.06em;
text-transform: uppercase;
background: #eef3ff;
border: 1px solid #dce6f7;
color: #2e4b82;
}
.headline {
margin: 0;
font-size: 0;
}
.subline {
display: none;
}
.form {
position: relative;
z-index: 10;
width: 100%;
padding: 40px 36px;
box-sizing: border-box; box-sizing: border-box;
margin: 160px auto 0; background: linear-gradient(180deg, rgba(255, 255, 255, 0.82) 0%, rgba(255, 255, 255, 0.94) 100%);
border: 1px solid rgba(120, 149, 203, 0.18);
border-radius: 26px;
box-shadow:
0 24px 80px rgba(88, 112, 156, 0.22),
inset 0 1px 0 rgba(255, 255, 255, 0.8);
transition: all 0.35s ease;
overflow: hidden;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
&::before {
content: '';
position: absolute;
inset: -36%;
background: conic-gradient(from 140deg, rgba(99, 102, 241, 0.12), rgba(34, 211, 238, 0.16), rgba(45, 212, 191, 0.12), rgba(99, 102, 241, 0.12));
transform: translate3d(0, 0, 0);
filter: blur(38px);
z-index: 0;
animation: form-glow 12s ease-in-out infinite;
opacity: 0.8;
}
&:hover {
transform: translateY(-2px);
box-shadow:
0 28px 96px rgba(88, 112, 156, 0.26),
inset 0 1px 0 rgba(255, 255, 255, 0.88);
}
:deep { :deep {
.el-input__wrapper { .el-input__wrapper {
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1) inset; background: rgba(255, 255, 255, 0.72);
background: rgba(0, 0, 0, 0.1); border: 1px solid rgba(120, 149, 203, 0.25);
border-radius: 14px;
box-shadow:
0 6px 18px rgba(36, 79, 140, 0.12),
inset 0 1px 0 rgba(255, 255, 255, 0.8);
transition: all 0.25s ease;
backdrop-filter: blur(8px);
&:hover {
border-color: rgba(120, 149, 203, 0.36);
background: rgba(255, 255, 255, 0.86);
} }
&.is-focus {
background: rgba(255, 255, 255, 0.96);
border-color: #6aa6ff;
box-shadow:
0 12px 28px rgba(106, 166, 255, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.94),
0 0 0 4px rgba(106, 166, 255, 0.22);
}
}
.el-input__inner {
color: #0f172a;
font-weight: 600;
&::placeholder {
color: #6b7280;
}
}
.el-input__prefix {
.el-icon {
color: #6b7280;
}
}
.el-input-group--append > .el-input__wrapper { .el-input-group--append > .el-input__wrapper {
border-top-right-radius: 0; border-top-right-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
@ -223,38 +442,218 @@ export default defineComponent({
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
} }
} }
.title {
color: #fff; .form-meta {
text-align: center; position: relative;
font-size: 24px; z-index: 1;
margin: 0 0 24px; display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 12px;
margin-bottom: 18px;
} }
.eyebrow {
margin: 0;
color: #6b7280;
font-size: 12px;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.title {
color: #0f172a;
font-size: 26px;
font-weight: 800;
margin: 4px 0 6px;
text-shadow: 0 10px 18px rgba(74, 88, 126, 0.2);
}
.title-desc {
margin: 0;
color: #4b5563;
font-size: 13px;
}
.tag {
height: 28px;
padding: 0 12px;
border-radius: 999px;
display: inline-flex;
align-items: center;
justify-content: center;
color: #0b1628;
font-weight: 700;
font-size: 12px;
}
.gradient {
background: linear-gradient(120deg, #34d399 0%, #22d3ee 50%, #60a5fa 100%);
box-shadow: 0 10px 25px rgba(52, 211, 153, 0.4);
}
.text { .text {
font-size: 16px; font-size: 16px;
position: relative;
z-index: 1;
:deep(.el-input__inner) { :deep(.el-input__inner) {
color: #fff; color: #0f172a;
height: 48px; height: 48px;
line-height: 48px; line-height: 48px;
&::placeholder { &::placeholder {
color: rgba(255, 255, 255, 0.2); color: #6b7280;
} }
} }
} }
.btn { .btn {
position: relative;
z-index: 1;
width: 100%; width: 100%;
height: 50px;
font-size: 16px;
font-weight: 750;
border-radius: 14px;
background: linear-gradient(135deg, #7bb6ff 0%, #6fe0c0 50%, #6ad5f3 100%);
border: none;
box-shadow:
0 10px 28px rgba(111, 224, 192, 0.35),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
transition: all 0.3s ease;
&:hover:not(:disabled) {
transform: translateY(-2px) scale(1.01);
box-shadow:
0 16px 38px rgba(111, 224, 192, 0.42),
inset 0 1px 0 rgba(255, 255, 255, 0.4);
}
&:active:not(:disabled) {
transform: translateY(0);
}
}
.divider {
position: relative;
z-index: 1;
display: flex;
align-items: center;
gap: 12px;
color: rgba(9, 8, 8, 0.7);
font-size: 12px;
margin: 10px 0 14px;
&::before,
&::after {
content: '';
flex: 1;
height: 1px;
background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0));
}
}
.btn-sso {
position: relative;
z-index: 1;
width: 100%;
height: 48px;
border-radius: 14px;
border: 1px solid rgba(120, 149, 203, 0.28);
color: #0f172a;
font-weight: 700;
letter-spacing: 0.02em;
background: linear-gradient(120deg, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0.82));
box-shadow: 0 10px 28px rgba(88, 112, 156, 0.18);
transition: all 0.25s ease;
&:hover {
background: rgba(255, 255, 255, 0.96);
border-color: rgba(120, 149, 203, 0.42);
transform: translateY(-2px);
} }
} }
} }
}
@keyframes blob-float {
0% {
transform: translate3d(0, 0, 0) scale(1);
}
50% {
transform: translate3d(-20px, 20px, 0) scale(1.05);
}
100% {
transform: translate3d(0, 0, 0) scale(1);
}
}
@keyframes blob-float-2 {
0% {
transform: translate3d(0, 0, 0) scale(1);
}
50% {
transform: translate3d(24px, -16px, 0) scale(1.08);
}
100% {
transform: translate3d(0, 0, 0) scale(1);
}
}
@keyframes blob-float-3 {
0% {
transform: translate(-50%, -50%) scale(1);
}
50% {
transform: translate(-48%, -52%) scale(1.06);
}
100% {
transform: translate(-50%, -50%) scale(1);
}
}
@keyframes form-glow {
0% {
transform: rotate(0deg) scale(1);
opacity: 0.9;
}
50% {
transform: rotate(180deg) scale(1.06);
opacity: 1;
}
100% {
transform: rotate(360deg) scale(1);
opacity: 0.9;
}
}
@media (max-width: 1080px) {
.login {
padding: 60px 22px;
.shell {
width: min(520px, 100%);
}
}
}
.change-lang { .change-lang {
position: fixed; position: fixed;
right: 20px; right: 20px;
top: 20px; top: 20px;
z-index: 100;
:deep { :deep {
.change-lang { .change-lang {
height: 24px; height: 24px;
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 8px;
padding: 4px 8px;
transition: all 0.3s ease;
&:hover { &:hover {
background: none; background: rgba(255, 255, 255, 0.3);
border-color: rgba(255, 255, 255, 0.4);
} }
.icon { .icon {
color: #fff; color: #fff;
} }

View File

@ -73,16 +73,17 @@ export default env => {
}, },
}, },
server: { server: {
host: '0.0.0.0', // listen on all interfaces so LAN IP works
port: 3001, port: 3001,
open: true, open: true,
proxy: { proxy: {
'/api': { '/api': {
target: 'http://localhost:8501', // 后端接口的域名 target: 'http://192.168.0.240:8501', // 后端接口的域名
changeOrigin: true, changeOrigin: true,
}, },
'/admin': { '/admin': {
target: 'http://localhost:8501', // 后端接口的域名 target: 'http://192.168.0.240:8501', // 后端接口的域名
changeOrigin: true, changeOrigin: true,
}, },
@ -95,7 +96,7 @@ export default env => {
// 强度计算模块 // 强度计算模块
'/strength-api': { '/strength-api': {
target: 'http://localhost:8501', target: 'http://192.168.0.240:8501',
changeOrigin: true, changeOrigin: true,
rewrite: path => path.replace(/^\/strength-api/, '') rewrite: path => path.replace(/^\/strength-api/, '')
} }