Ver código fonte

新增LoginLayout; 重做Login页面使用新的登录布局;创建字体发光的样式修改登录页顶部标题;

画安 1 mês atrás
pai
commit
004fe8bdb6

BIN
src/assets/images/login-background.png


+ 1 - 1
src/layouts/DashboardLayout.vue

@@ -149,7 +149,7 @@ export default {
     },
     data() {
         return {
-            title: '交通信号控制平台',
+            title: '灵智交通信号控制平台',
         }
     },
     methods: {

+ 147 - 0
src/layouts/LoginLayout.vue

@@ -0,0 +1,147 @@
+<template>
+    <div class="fluid-dashboard">
+        <div class="frame-top">
+            <div class="title neon-pulse-style">{{ title }}</div>
+        </div>
+
+        <div class="frame-bottom"></div>
+
+        <slot name="background"></slot>
+
+        <div class="ui-layer">
+
+            <main class="main-layout" :class="layoutClass">
+                <slot name="main"></slot>
+            </main>
+        </div>
+
+    </div>
+</template>
+
+<script>
+
+
+export default {
+    name: 'LoginLayout',
+    mixins: [],
+    components: {
+        
+    },
+    props: {
+        // 接收外部传入的 class,用于动态切换 CSS 网格布局
+        // 例如传入 "special-situation-monitoring"
+        layoutClass: {
+            type: String,
+            default: ''
+        }
+    },
+    data() {
+        return {
+            title: '灵智交通信号控制平台',
+        }
+    },
+    methods: {
+        
+    }
+}
+</script>
+
+<style scoped>
+/* ================= 根容器 ================= */
+.fluid-dashboard {
+    width: 100vw;
+    height: 100vh;
+    position: relative;
+    overflow: hidden;
+    background: #050a17;
+    /* 兜底深色背景 */
+}
+
+/* ================= 大屏装饰边框 ================= */
+.frame-top,
+.frame-left,
+.frame-right,
+.frame-bottom {
+    position: absolute;
+    pointer-events: none;
+    /* 【核心】鼠标事件穿透,不挡底层交互 */
+    z-index: 50;
+    /* 层级高于 UI,低于弹窗 */
+}
+
+.frame-top {
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100px;
+    background: url('@/assets/images/layout-top.png') no-repeat center top;
+    background-size: 100% 100%;
+}
+
+.frame-top .title {
+    font-family: var(--title-font-family);
+    font-size: 48px;
+    color: #707070;
+    line-height: 63px;
+    text-align: center;
+    font-style: normal;
+    text-transform: none;
+    /* background: linear-gradient(90deg, #9ED3FD 0%, #FFFFFF 100%); */
+    -webkit-background-clip: text;
+    -webkit-text-fill-color: transparent;
+}
+
+
+.frame-left {
+    top: 10px;
+    left: 0;
+    width: 16px;
+    height: calc(100% - 10px - 40px);
+    background: url('@/assets/images/layout-left.png') no-repeat left center;
+    background-size: 100% 100%;
+}
+
+.frame-right {
+    top: 10px;
+    right: 0;
+    width: 16px;
+    height: calc(100% - 10px - 40px);
+    background: url('@/assets/images/layout-right.png') no-repeat right center;
+    background-size: 100% 100%;
+}
+
+.frame-bottom {
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    height: 17px;
+    /* background: url('@/assets/images/layout-bottom.png') no-repeat center bottom; */ 
+    background-size: 100% 100%;
+}
+
+/* ================= UI 层与网格布局 ================= */
+.ui-layer {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    z-index: 2;
+    pointer-events: none;
+    /* 让鼠标穿透点到下层的地图 */
+    display: grid;
+    grid-template-rows: 80px 1fr;
+    /* 头部 80px,其余给主体 */
+}
+
+/* --- 主体网格 --- */
+.main-layout {
+    height: 100%;
+    box-sizing: border-box;
+    pointer-events: none;
+}
+
+.main-layout > * {
+    pointer-events: auto; 
+}
+</style>

+ 44 - 0
src/styles/base.css

@@ -135,4 +135,48 @@ html, body {
 
 ::-webkit-scrollbar-corner {
   background: transparent; 
+}
+
+.neon-pulse-style {
+
+    letter-spacing: 4px; /* 增加字间距 */
+    
+    /* 2. 文字渐变:模拟霓虹灯管的亮芯 */
+    background: linear-gradient(
+        to bottom,
+        #ffffff 20%,   /* 核心最亮处 */
+        #b3e5fc 50%,   /* 浅蓝色过渡 */
+        #4fc3f7 100%   /* 底部稍深 */
+    );
+
+    /* 3. 核心:霓虹灯发光效果 (多层 drop-shadow) */
+    /* 第一层:近距离白色高亮 */
+    /* 第二层:中距离主题色发光 */
+    /* 第三层:远距离环境光晕 */
+    filter: 
+        drop-shadow(0 0 5px rgba(255, 255, 255, 0.8))
+        drop-shadow(0 0 15px rgba(79, 195, 247, 0.6))
+        drop-shadow(0 0 30px rgba(3, 169, 244, 0.4));
+
+    /* 4. 动画:让霓虹灯“活”起来 */
+    animation: neon-pulse 3s ease-in-out infinite;
+    transition: all 0.3s ease;
+}
+
+/* 霓虹灯呼吸动画:模拟电流不稳定的真实感 */
+@keyframes neon-pulse {
+    0%, 100% {
+        filter: 
+            drop-shadow(0 0 5px rgba(255, 255, 255, 0.8))
+            drop-shadow(0 0 15px rgba(79, 195, 247, 0.6))
+            drop-shadow(0 0 30px rgba(3, 169, 244, 0.4));
+        opacity: 1;
+    }
+    50% {
+        filter: 
+            drop-shadow(0 0 8px rgba(255, 255, 255, 0.9))
+            drop-shadow(0 0 22px rgba(79, 195, 247, 0.8))
+            drop-shadow(0 0 45px rgba(3, 169, 244, 0.6));
+        opacity: 0.95; /* 微微闪烁 */
+    }
 }

+ 87 - 124
src/views/Login.vue

@@ -1,78 +1,86 @@
 <template>
-  <div class="page">
-    <div class="bg"></div>
-    <div class="ai-cloud-ring" aria-hidden="true"></div>
-    <div class="split-door" :class="{ opening: isDoorOpening }" aria-hidden="true">
-      <div class="door left"></div>
-      <div class="door right" @animationend="handleDoorEnd"></div>
-    </div>
-    <div class="header-deco"></div>
-    <!-- <div class="top-title">智慧交通信号控制管理平台</div> -->
-    <div class="content">
-      <!-- 左侧酷炫区域 -->
-      <div class="left">
-        <div class="ellipse-area">
-          <img class="ellipse" :src="require('@/assets/ellipse-line.png')" alt="ellipse" />
-          <!-- 沿椭圆的流光:不旋转椭圆图,只做覆盖层沿线跑动 -->
-          <div class="ellipse-glow"></div>
-          <div class="icon icon-1"><img :src="require('@/assets/icon-upload.png')" width="87px" height="87px" /></div>
-          <div class="icon icon-2"><img :src="require('@/assets/icon-webcam.png')" width="87px" height="87px" /></div>
-          <div class="icon icon-3"><img :src="require('@/assets/icon-shield.png')" width="87px" height="87px" /></div>
-          <div class="icon icon-4"><img :src="require('@/assets/icon-setting.png')" width="87px" height="87px" /></div>
+  <LoginLayout >
+
+    <!-- 背景 -->
+    <template #background>
+      <div class="login-bg"></div>
+    </template>
+
+    <template #main>
+      <div class="page">
+        <div class="ai-cloud-ring" aria-hidden="true"></div>
+        <div class="split-door" :class="{ opening: isDoorOpening }" aria-hidden="true">
+          <div class="door left"></div>
+          <div class="door right" @animationend="handleDoorEnd"></div>
         </div>
-      </div>
-
-      <!-- 右侧登录面板 -->
-      <div class="right">
-        <div class="panel">
-            <div class="panel-inner">
-            
-            <div class="panel-title">账号登录</div>
-
-            <div class="field">
-                <img class="i" :src="require('@/assets/i_user.png')" />
-                <span class="field-label">账号</span>
-                <input class="inp" v-model.trim="username" placeholder="请输入账号" />
+        <div class="content">
+          <!-- 左侧酷炫区域 -->
+          <div class="left">
+            <div class="ellipse-area">
+              <img class="ellipse" :src="require('@/assets/ellipse-line.png')" alt="ellipse" />
+              <!-- 沿椭圆的流光:不旋转椭圆图,只做覆盖层沿线跑动 -->
+              <div class="ellipse-glow"></div>
+              <div class="icon icon-1"><img :src="require('@/assets/icon-upload.png')" width="87px" height="87px" /></div>
+              <div class="icon icon-2"><img :src="require('@/assets/icon-webcam.png')" width="87px" height="87px" /></div>
+              <div class="icon icon-3"><img :src="require('@/assets/icon-shield.png')" width="87px" height="87px" /></div>
+              <div class="icon icon-4"><img :src="require('@/assets/icon-setting.png')" width="87px" height="87px" /></div>
             </div>
-
-            <div class="field">
-                <img class="i" :src="require('@/assets/i_lock.png')" />
-                <span class="field-label">密码</span>
-                <input class="inp" type="password" v-model.trim="password" placeholder="请输入密码" />
-            </div>
-
-            <div class="row">
-                <div class="field cap-field">
-                <img class="i" :src="require('@/assets/i_captcha.png')" />
-                <span class="field-label">验证码</span>
-                <input class="inp" v-model.trim="captchaInput" placeholder="请输入验证码" />
+          </div>
+    
+          <!-- 右侧登录面板 -->
+          <div class="right">
+            <div class="panel">
+                <div class="panel-inner">
+                
+                <div class="panel-title">账号登录</div>
+    
+                <div class="field">
+                    <img class="i" :src="require('@/assets/i_user.png')" />
+                    <span class="field-label">账号</span>
+                    <input class="inp" v-model.trim="username" placeholder="请输入账号" />
                 </div>
-                <CaptchaCanvas v-model="captchaCode" />
-            </div>
-            
-            <div class="hint" v-if="hint">{{ hint }}</div>
-            <button class="btn" @click="onLogin">立即登录</button>
-
-            </div>
-         </div>
+    
+                <div class="field">
+                    <img class="i" :src="require('@/assets/i_lock.png')" />
+                    <span class="field-label">密码</span>
+                    <input class="inp" type="password" v-model.trim="password" placeholder="请输入密码" />
+                </div>
+    
+                <div class="row">
+                    <div class="field cap-field">
+                    <img class="i" :src="require('@/assets/i_captcha.png')" />
+                    <span class="field-label">验证码</span>
+                    <input class="inp" v-model.trim="captchaInput" placeholder="请输入验证码" />
+                    </div>
+                    <CaptchaCanvas v-model="captchaCode" />
+                </div>
+                
+                <div class="hint" v-if="hint">{{ hint }}</div>
+                <button class="btn" @click="onLogin">立即登录</button>
+    
+                </div>
+             </div>
+          </div>
+        </div>
+        <div class="page-dim" :class="{ opening: isDoorOpening }" aria-hidden="true"></div>
+        <div class="copyright">
+          <img class="copyright-logo" :src="require('@/assets/images/logo.png')" />
+          <div>北京东土正创科技有限公司</div>
+        </div>
       </div>
-    </div>
-    <div class="page-dim" :class="{ opening: isDoorOpening }" aria-hidden="true"></div>
-    <div class="copyright">
-      <img class="copyright-logo" :src="require('@/assets/images/logo.png')" />
-    </div>
-  </div>
+    </template>
+
+  </LoginLayout>
 </template>
 
 <script>
 import CaptchaCanvas from "@/components/CaptchaCanvas.vue";
+import LoginLayout from "@/layouts/LoginLayout.vue";
 import { mockLogin } from "@/mock/api";
-import Toast from "@/plugins/toast";
 
 export default {
-  // eslint-disable-next-line vue/multi-word-component-names
-  name: "Login",
-  components: { CaptchaCanvas },
+  name: "LoginPage",
+  components: { CaptchaCanvas, LoginLayout },
   created() {
     // 提前预加载 Cesium 瓦片
     import('@/utils/cesiumPreloader').then(m => m.default.start());
@@ -143,6 +151,12 @@ export default {
 </script>
 
 <style scoped>
+.login-bg {
+  background: url('@/assets/images/login-background.png') no-repeat center/cover;
+  width: 100%;
+  height: 100%;
+}
+
 .page{
   width: 100vw; height: 100vh;
   position: relative;
@@ -150,38 +164,6 @@ export default {
   --s: 1;
  }
 
-.bg{
-  position:absolute;
-  inset:0;
-  background: url("~@/assets/ai_bg.png") center/cover no-repeat;
-  filter: saturate(1.05);
-  z-index: 0;
-}
-
-.header-deco{
-  position:absolute;
-  top: 0; left: 0; right: 0;
-  height: calc(var(--s) * 86px);
-  background: url("~@/assets/header_deco1.png") center/cover no-repeat;
-  pointer-events:none;
-  opacity: 0.95;
-  z-index: 2;
-}
-
-.top-title{
-  position:absolute;
-  top: calc(var(--s) * 20px);
-  left: 50%;
-  transform: translateX(-50%);
-  font-size: calc(var(--s) * 24px);
-  letter-spacing: calc(var(--s) * 3px);
-  font-weight: 700;
-  color: #e6f6ff;
-  text-shadow: 0 0 calc(var(--s) * 12px) rgba(80,200,255,0.45);
-  pointer-events:none;
-  z-index: 3; /* 关键:必须压过 content */
-}
-
 .content{
   position:absolute;
   inset: 0;
@@ -257,10 +239,10 @@ export default {
 
 /* 按你给的比例调过 */
 
-.icon-1{ left: 16.8%; top: 81%; }   /* 盾牌 */
-.icon-2{ left: 41.5%; top: 78%; }   /* 人像 */
-.icon-3{ left: 61.5%;top: 68.5%;} /* 中间图标 */
-.icon-4{ left: 80.5%; top: 52%;}   /* 齿轮 */
+.icon-1{ left: 16.8%; top: 87%; }   /* 盾牌 */
+.icon-2{ left: 41.5%; top: 84%; }   /* 人像 */
+.icon-3{ left: 61.5%;top: 73%;} /* 中间图标 */
+.icon-4{ left: 80.5%; top: 56%;}   /* 齿轮 */
 
 
 /* 单独给每个球不同浮动幅度(可选,效果更高级) */
@@ -444,7 +426,7 @@ export default {
   z-index: 1; /* 在 bg(0) 上面,但不压住 header/title 可再调 */
   
   /* ✅必须和 .bg 使用同一张图 + 同样的 size/position,才能精确对齐 */
-  background-image: url('~@/assets/ai_bg.png'); /* ← 改成你真实路径 */
+  background-image: url('~@/assets/images/login-background.png'); /* ← 改成你真实路径 */
   background-repeat: no-repeat;
   background-size: cover;
   background-position: center center;
@@ -507,7 +489,7 @@ export default {
   position: absolute;
   inset: 0;
 
-  background: url("~@/assets/ai_bg.png") center/cover no-repeat; /* 跟 .bg 完全一致 */
+  background: url("~@/assets/images/login-background.png") center/cover no-repeat; /* 跟 .bg 完全一致 */
   filter: brightness(1.03) contrast(1.04);
   will-change: transform;
 }
@@ -603,34 +585,15 @@ export default {
 .copyright {
   display: flex;
   align-items: center;
+  flex-direction: column;
   font-size: 18px;
   color: #FFF;
   line-height: 30px;
   text-align: center;
   position: absolute;
   bottom: 20px;
-  left: calc(50% - 35px);
-}
-
-.copyright::before,
-.copyright::after {
-  content: "";
-  display: block;
-  width: 4px;
-  height: 4px;
-  border-radius: 2px;
-  background: #e7e7e7;
-}
-
-.copyright::before {
-  margin-right: 10px;
-}
-
-.copyright::after {
-  margin-left: 10px;
-}
-.copyright-logo {
-  width: 212.52px;
-  height: 43.5px;
+  left: 0;
+  justify-content: center;
+  width: 100%;
 }
 </style>