|
@@ -1,369 +0,0 @@
|
|
|
-<template>
|
|
|
|
|
- <LoginLayout >
|
|
|
|
|
-
|
|
|
|
|
- <!-- 背景 -->
|
|
|
|
|
- <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>
|
|
|
|
|
- <div class="page">
|
|
|
|
|
- <div class="content">
|
|
|
|
|
- <!-- 左侧酷炫区域 -->
|
|
|
|
|
- <div class="left">
|
|
|
|
|
-
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 右侧登录面板 -->
|
|
|
|
|
- <div class="right">
|
|
|
|
|
- <div class="login-container">
|
|
|
|
|
- <LoginForm></LoginForm>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="copyright">
|
|
|
|
|
- <img class="copyright-logo" :src="require('@/assets/images/logo.png')" />
|
|
|
|
|
- <div>北京东土正创科技有限公司</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </template>
|
|
|
|
|
-
|
|
|
|
|
- </LoginLayout>
|
|
|
|
|
-</template>
|
|
|
|
|
-
|
|
|
|
|
-<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,
|
|
|
|
|
- WaveCanvas
|
|
|
|
|
- },
|
|
|
|
|
- created() {
|
|
|
|
|
- // 提前预加载 Cesium 瓦片
|
|
|
|
|
- import('@/utils/cesiumPreloader').then(m => m.default.start());
|
|
|
|
|
- },
|
|
|
|
|
- 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>
|
|
|
|
|
-
|
|
|
|
|
-<style scoped>
|
|
|
|
|
-.login-bg {
|
|
|
|
|
- background: url('@/assets/images/login-background.png') no-repeat center/cover;
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- position: absolute;
|
|
|
|
|
- top: 0;
|
|
|
|
|
- left: 0;
|
|
|
|
|
-}
|
|
|
|
|
-.login-container {
|
|
|
|
|
- /* * 【自适应魔法】:计算当前屏幕与 1920 宽度的比例。
|
|
|
|
|
- * clamp(最小缩放比例, 动态计算比例, 最大缩放比例)
|
|
|
|
|
- * 当屏幕小于 1920 时,--s 会小于 1;当屏幕等于 1920 时,--s 为 1。
|
|
|
|
|
- */
|
|
|
|
|
- --s: clamp(0.5, 100vw / 1920, 1.2);
|
|
|
|
|
-
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: flex-end;
|
|
|
|
|
-
|
|
|
|
|
- /* 右侧边距也用 clamp 做动态响应:最小 20px,推荐 8vw,最大 150px */
|
|
|
|
|
- padding-right: clamp(20px, 8vw, 150px);
|
|
|
|
|
- box-sizing: border-box;
|
|
|
|
|
- pointer-events: auto;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.page{
|
|
|
|
|
- width: 100vw; height: 100vh;
|
|
|
|
|
- position: relative;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
- --s: 1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-.content{
|
|
|
|
|
- position:absolute;
|
|
|
|
|
- inset: 0;
|
|
|
|
|
- display:grid;
|
|
|
|
|
- grid-template-columns: 1fr 1fr;
|
|
|
|
|
- gap: clamp(calc(var(--s) * 14px), 1.8vw, calc(var(--s) * 28px));
|
|
|
|
|
- padding: clamp(calc(var(--s) * 14px), 2.4vw, calc(var(--s) * 30px));
|
|
|
|
|
- padding-top: calc(var(--s) * 60px); /* 给头部留空间 */
|
|
|
|
|
- align-items:center;
|
|
|
|
|
- z-index: 1;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/* 左侧 */
|
|
|
|
|
-.left{ min-width: 0; }
|
|
|
|
|
-
|
|
|
|
|
-/* 右侧面板 */
|
|
|
|
|
-.right{
|
|
|
|
|
- min-width: 0;
|
|
|
|
|
- display:flex;
|
|
|
|
|
- justify-content:center;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/* 版权信息 */
|
|
|
|
|
-.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: 0;
|
|
|
|
|
- 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>
|
|
|