Bläddra i källkod

feat: 替吟码提交登录页修改代码及文件

sequoia tungfang 3 veckor sedan
förälder
incheckning
ed98b254bc

BIN
src/assets/icon_green_left.png


BIN
src/assets/icon_green_person.png


BIN
src/assets/icon_red_left.png


BIN
src/assets/icon_red_person.png


BIN
src/assets/icon_yellow_left.png


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


+ 257 - 0
src/components/WaveCanvas.vue

@@ -0,0 +1,257 @@
+<template>
+  <canvas ref="waveCanvas" class="wave-canvas"></canvas>
+</template>
+
+<script>
+export default {
+  name: "WaveCanvas",
+  data() {
+    return {
+      canvas: null,
+      ctx: null,
+      animationId: null,
+      time: 0,
+      waves: [],
+      particles: []
+    };
+  },
+  mounted() {
+    this.initCanvas();
+    this.initWaves();
+    this.initParticles();
+    this.animate();
+    window.addEventListener("resize", this.handleResize);
+  },
+  beforeDestroy() {
+    if (this.animationId) {
+      cancelAnimationFrame(this.animationId);
+    }
+    window.removeEventListener("resize", this.handleResize);
+  },
+  methods: {
+    initCanvas() {
+      this.canvas = this.$refs.waveCanvas;
+      this.ctx = this.canvas.getContext("2d");
+      this.setCanvasSize();
+    },
+    setCanvasSize() {
+      const parent = this.canvas.parentElement;
+      this.canvas.width = parent.clientWidth;
+      this.canvas.height = parent.clientHeight;
+    },
+    handleResize() {
+      this.setCanvasSize();
+      this.initParticles();
+    },
+    initWaves() {
+      // 创建多层波浪参数
+      this.waves = [
+        {
+          amplitude: 30,
+          frequency: 0.01,
+          speed: 0.02,
+          yOffset: 0.7,
+          color: "rgba(64, 156, 255, 0.4)",
+          lineWidth: 2
+        },
+        {
+          amplitude: 25,
+          frequency: 0.015,
+          speed: 0.025,
+          yOffset: 0.75,
+          color: "rgba(100, 181, 246, 0.3)",
+          lineWidth: 1.5
+        },
+        {
+          amplitude: 20,
+          frequency: 0.008,
+          speed: 0.015,
+          yOffset: 0.8,
+          color: "rgba(144, 202, 249, 0.25)",
+          lineWidth: 1
+        },
+        {
+          amplitude: 35,
+          frequency: 0.012,
+          speed: 0.018,
+          yOffset: 0.65,
+          color: "rgba(64, 156, 255, 0.2)",
+          lineWidth: 1.5
+        }
+      ];
+    },
+    initParticles() {
+      this.particles = [];
+      const width = this.canvas.width;
+      const height = this.canvas.height;
+      
+      // 创建点阵粒子
+      const cols = Math.floor(width / 15);
+      const rows = Math.floor(height / 15);
+      
+      for (let i = 0; i < cols; i++) {
+        for (let j = 0; j < rows; j++) {
+          if (Math.random() > 0.6) {
+            this.particles.push({
+              x: i * 15 + Math.random() * 10,
+              y: j * 15 + Math.random() * 10,
+              baseY: j * 15,
+              size: Math.random() * 1.5 + 0.5,
+              opacity: Math.random() * 0.5 + 0.2,
+              speed: Math.random() * 0.5 + 0.2,
+              phase: Math.random() * Math.PI * 2
+            });
+          }
+        }
+      }
+    },
+    drawWave(wave, index) {
+      const ctx = this.ctx;
+      const width = this.canvas.width;
+      const height = this.canvas.height;
+      const baseY = height * wave.yOffset;
+      
+      ctx.beginPath();
+      ctx.strokeStyle = wave.color;
+      ctx.lineWidth = wave.lineWidth;
+      
+      // 绘制波浪线
+      for (let x = 0; x <= width; x += 2) {
+        const y = baseY + 
+          Math.sin(x * wave.frequency + this.time * wave.speed + index) * wave.amplitude +
+          Math.sin(x * wave.frequency * 2 + this.time * wave.speed * 1.5) * (wave.amplitude * 0.5);
+        
+        if (x === 0) {
+          ctx.moveTo(x, y);
+        } else {
+          ctx.lineTo(x, y);
+        }
+      }
+      
+      ctx.stroke();
+      
+      // 填充波浪下方渐变
+      ctx.lineTo(width, height);
+      ctx.lineTo(0, height);
+      ctx.closePath();
+      
+      const gradient = ctx.createLinearGradient(0, baseY - wave.amplitude, 0, height);
+      gradient.addColorStop(0, wave.color.replace(/[\d.]+\)$/, "0.1)"));
+      gradient.addColorStop(0.5, wave.color.replace(/[\d.]+\)$/, "0.05)"));
+      gradient.addColorStop(1, "transparent");
+      
+      ctx.fillStyle = gradient;
+      ctx.fill();
+    },
+    drawParticles() {
+      const ctx = this.ctx;
+      const width = this.canvas.width;
+      const height = this.canvas.height;
+      
+      this.particles.forEach(particle => {
+        // 粒子随波浪波动
+        const waveY = Math.sin(particle.x * 0.01 + this.time * 0.02) * 20 +
+                      Math.sin(particle.x * 0.02 + this.time * 0.03) * 10;
+        
+        const y = particle.baseY + waveY * particle.speed;
+        
+        // 只在底部区域显示粒子
+        if (y > height * 0.5) {
+          const opacity = particle.opacity * (1 - (y - height * 0.5) / (height * 0.5));
+          
+          ctx.beginPath();
+          ctx.arc(particle.x, y, particle.size, 0, Math.PI * 2);
+          ctx.fillStyle = `rgba(100, 200, 255, ${Math.max(0, opacity)})`;
+          ctx.fill();
+          
+          // 添加发光效果
+          if (opacity > 0.3) {
+            ctx.beginPath();
+            ctx.arc(particle.x, y, particle.size * 3, 0, Math.PI * 2);
+            ctx.fillStyle = `rgba(100, 200, 255, ${opacity * 0.2})`;
+            ctx.fill();
+          }
+        }
+      });
+    },
+    drawGrid() {
+      const ctx = this.ctx;
+      const width = this.canvas.width;
+      const height = this.canvas.height;
+      
+      // 绘制淡淡的网格线
+      ctx.strokeStyle = "rgba(64, 156, 255, 0.03)";
+      ctx.lineWidth = 0.5;
+      
+      const gridSize = 30;
+      
+      for (let x = 0; x <= width; x += gridSize) {
+        ctx.beginPath();
+        ctx.moveTo(x, height * 0.5);
+        ctx.lineTo(x, height);
+        ctx.stroke();
+      }
+      
+      for (let y = Math.floor(height * 0.5); y <= height; y += gridSize) {
+        ctx.beginPath();
+        ctx.moveTo(0, y);
+        ctx.lineTo(width, y);
+        ctx.stroke();
+      }
+    },
+    drawGlow() {
+      const ctx = this.ctx;
+      const width = this.canvas.width;
+      const height = this.canvas.height;
+      
+      // 底部发光效果
+      const gradient = ctx.createLinearGradient(0, height - 150, 0, height);
+      gradient.addColorStop(0, "transparent");
+      gradient.addColorStop(0.5, "rgba(64, 156, 255, 0.1)");
+      gradient.addColorStop(1, "rgba(64, 156, 255, 0.25)");
+      
+      ctx.fillStyle = gradient;
+      ctx.fillRect(0, height - 150, width, 150);
+    },
+    animate() {
+      const ctx = this.ctx;
+      const width = this.canvas.width;
+      const height = this.canvas.height;
+      
+      // 清空画布
+      ctx.clearRect(0, 0, width, height);
+      
+      // 绘制网格
+      this.drawGrid();
+      
+      // 绘制波浪
+      this.waves.forEach((wave, index) => {
+        this.drawWave(wave, index);
+      });
+      
+      // 绘制粒子
+      this.drawParticles();
+      
+      // 绘制发光效果
+      this.drawGlow();
+      
+      // 更新时间
+      this.time += 1;
+      
+      // 继续动画
+      this.animationId = requestAnimationFrame(this.animate.bind(this));
+    }
+  }
+};
+</script>
+
+<style scoped>
+.wave-canvas {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  pointer-events: none;
+}
+</style>

+ 230 - 4
src/views/Login.vue

@@ -4,6 +4,48 @@
     <!-- 背景 -->
     <template #background>
       <div class="login-bg"></div>
+      <!-- 红绿灯动画 -->
+      <div class="traffic-light-system">
+        <!-- 主红绿灯(直行) -->
+        <div class="traffic-light main-light">
+          <div class="light red" :class="{ active: mainLight === 'red' }"></div>
+          <div class="light yellow" :class="{ active: mainLight === 'yellow' }"></div>
+          <div class="light green" :class="{ active: mainLight === 'green' }"></div>
+        </div>
+        <!-- 左拐灯 -->
+        <div class="left-turn-light">
+          <div class="arrow-light">
+            <img 
+              v-if="leftLight === 'red'" 
+              :src="require('@/assets/icon_red_left.png')" 
+              alt="左拐红灯"
+            />
+            <img 
+              v-else-if="leftLight === 'yellow'" 
+              :src="require('@/assets/icon_yellow_left.png')" 
+              alt="左拐黄灯"
+            />
+            <img 
+              v-else 
+              :src="require('@/assets/icon_green_left.png')" 
+              alt="左拐绿灯"
+            />
+          </div>
+        </div>
+        <!-- 人行道灯 -->
+        <div class="pedestrian-light">
+          <div class="person-light" :class="{ active: pedestrianLight === 'red' }">
+            <img :src="require('@/assets/icon_red_person.png')" alt="红灯" class="person-img" />
+          </div>
+          <div class="person-light" :class="{ active: pedestrianLight === 'green' }">
+            <img :src="require('@/assets/icon_green_person.png')" alt="绿灯" class="person-img" />
+          </div>
+        </div>
+      </div>
+      <!-- Canvas 波浪动画 -->
+      <div class="wave-canvas-container">
+        <WaveCanvas />
+      </div>
     </template>
 
     <template #main>
@@ -35,12 +77,14 @@
 <script>
 import LoginLayout from "@/layouts/LoginLayout.vue";
 import LoginForm from "@/components/ui/LoginForm.vue";
+import WaveCanvas from "@/components/WaveCanvas.vue";
 
 export default {
   name: "LoginPage",
   components: { 
     LoginLayout,
-    LoginForm
+    LoginForm,
+    WaveCanvas
   },
   created() {
     // 提前预加载 Cesium 瓦片
@@ -48,22 +92,73 @@ export default {
   },
   data() {
     return {
-      
+      mainLight: 'green',      // 直行灯: green, yellow, red
+      leftLight: 'red',        // 左拐灯: green, yellow, red
+      pedestrianLight: 'green', // 人行道灯: green, red
+      lightTimer: null,
+      currentPhase: 0,         // 0: 直行绿, 1: 黄灯, 2: 左拐绿
     };
   },
   computed: {
     
   },
   mounted() {
-    
+    this.startTrafficLightCycle();
   },
   beforeDestroy() {
-    
+    if (this.lightTimer) {
+      clearTimeout(this.lightTimer);
+    }
   },
 
   methods: {
+    startTrafficLightCycle() {
+      // 状态0: 直行绿灯10秒 + 人行道绿灯 + 左拐红灯
+      this.currentPhase = 0;
+      this.mainLight = 'green';
+      this.leftLight = 'red';
+      this.pedestrianLight = 'green';
+      
+      this.lightTimer = setTimeout(() => {
+        this.switchToYellowPhase();
+      }, 10000);
+    },
     
+    switchToYellowPhase() {
+      // 状态1: 黄灯3秒 + 直行灭(实际变黄)+ 左拐红 + 人行道红
+      this.currentPhase = 1;
+      this.mainLight = 'yellow';
+      this.leftLight = 'red';
+      this.pedestrianLight = 'red';
+      
+      this.lightTimer = setTimeout(() => {
+        this.switchToLeftTurnPhase();
+      }, 3000);
+    },
+    
+    switchToLeftTurnPhase() {
+      // 状态2: 左拐绿灯10秒 + 直行红灯 + 人行道红灯
+      this.currentPhase = 2;
+      this.mainLight = 'red';
+      this.leftLight = 'green';
+      this.pedestrianLight = 'red';
+      
+      this.lightTimer = setTimeout(() => {
+        this.switchToYellowPhase2();
+      }, 10000);
+    },
     
+    switchToYellowPhase2() {
+      // 状态3: 黄灯3秒 + 左拐黄灯 + 直行红灯 + 人行道红灯
+      this.currentPhase = 3;
+      this.mainLight = 'red';
+      this.leftLight = 'yellow';
+      this.pedestrianLight = 'red';
+      
+      this.lightTimer = setTimeout(() => {
+        this.startTrafficLightCycle(); // 重新开始循环
+      }, 3000);
+    }
   }
 };
 </script>
@@ -140,4 +235,135 @@ export default {
   justify-content: center;
   width: 100%;
 }
+
+.copyright-logo {
+  width: 100px;
+  margin-bottom: 10px;
+}
+
+/* ================= 红绿灯系统 ================= */
+.traffic-light-system {
+  position: absolute;
+  left: 30%;
+  top: 25%;
+  z-index: 10;
+}
+
+/* 主红绿灯(直行) */
+.traffic-light {
+  position: absolute;
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  padding: 6px;
+}
+
+.main-light {
+  left: 67px;
+  top: 0px;
+}
+
+.left-light {
+  left: 0;
+  top: 0;
+}
+
+/* 左拐箭头灯 */
+.left-turn-light {
+  position: absolute;
+  left: 4px;
+  top: 4px;
+}
+
+.arrow-light {
+  width: 36px;
+  height: 36px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  transition: all 0.3s ease;
+}
+
+.arrow-light img {
+  width: 100%;
+  height: 100%;
+  object-fit: contain;
+  filter: drop-shadow(none);
+}
+
+.light {
+  width: 30px;
+  height: 30px;
+  border-radius: 50%;
+  opacity: 0.15;
+  transition: all 0.3s ease;
+  background: radial-gradient(circle at 30% 30%, rgba(100, 100, 100, 0.5), rgba(50, 50, 50, 0.3));
+}
+
+.light.red {
+  background: radial-gradient(circle at 30% 30%, #ff4444, #cc0000);
+}
+
+.light.red.active {
+  opacity: 1;
+  box-shadow: 0 0 15px #ff4444, 0 0 30px #ff4444, inset 0 0 10px rgba(255, 100, 100, 0.5);
+}
+
+.light.yellow {
+  background: radial-gradient(circle at 30% 30%, #ffcc00, #ff9900);
+}
+
+.light.yellow.active {
+  opacity: 1;
+  box-shadow: 0 0 15px #ffcc00, 0 0 30px #ffcc00, inset 0 0 10px rgba(255, 200, 100, 0.5);
+}
+
+.light.green {
+  background: radial-gradient(circle at 30% 30%, #00ff44, #00cc33);
+}
+
+.light.green.active {
+  opacity: 1;
+  box-shadow: 0 0 15px #00ff44, 0 0 30px #00ff44, inset 0 0 10px rgba(100, 255, 150, 0.5);
+}
+
+/* 人行道灯 */
+.pedestrian-light {
+  position: absolute;
+  left: 240px;
+  top: 125px;
+  width: 36px;
+  height: 80px;
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.person-light {
+  width: 36px;
+  height: 36px;
+  opacity: 0;
+  transition: all 0.3s ease;
+}
+
+.person-light.active {
+  opacity: 1;
+}
+
+.person-img {
+  width: 100%;
+  height: 100%;
+  object-fit: contain;
+}
+
+/* ================= Canvas 波浪容器 ================= */
+.wave-canvas-container {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  height: 400px;
+  z-index: 5;
+  pointer-events: none;
+}
 </style>