|
|
|
@ -1,50 +1,194 @@ |
|
|
|
<template> |
|
|
|
<div class="login"> |
|
|
|
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form"> |
|
|
|
<h3 class="title">客户 GeoTag管理后台</h3> |
|
|
|
<el-form-item prop="username"> |
|
|
|
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号"> |
|
|
|
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" /> |
|
|
|
</el-input> |
|
|
|
</el-form-item> |
|
|
|
<el-form-item prop="password"> |
|
|
|
<el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码" |
|
|
|
@keyup.enter.native="handleLogin"> |
|
|
|
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" /> |
|
|
|
</el-input> |
|
|
|
</el-form-item> |
|
|
|
<el-form-item prop="code"> |
|
|
|
<el-input v-model="loginForm.code" auto-complete="off" placeholder="谷歌验证码" style="width: 100%" |
|
|
|
@keyup.enter.native="handleLogin"> |
|
|
|
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" /> |
|
|
|
</el-input> |
|
|
|
<!-- <div class="login-code"> |
|
|
|
<img :src="codeUrl" @click="getCode" class="login-code-img"/> |
|
|
|
</div> --> |
|
|
|
</el-form-item> |
|
|
|
<!-- 人机验证 --> |
|
|
|
<!-- <el-form-item prop='validateCode'> |
|
|
|
<el-row :span="24"> |
|
|
|
<el-col :span="24"> |
|
|
|
<reCaptcha :sitekey="key" @getValidateCode='getValidateCode' v-model="loginForm.validateCode"></reCaptcha> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
</el-form-item> --> |
|
|
|
|
|
|
|
<!-- <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox> --> |
|
|
|
<el-form-item style="width:100%;"> |
|
|
|
<el-button :loading="loading" size="medium" type="waming" style="width:100%;" |
|
|
|
@click.native.prevent="handleLogin"> |
|
|
|
<span v-if="!loading">登 录</span> |
|
|
|
<span v-else>登 录 中...</span> |
|
|
|
</el-button> |
|
|
|
</el-form-item> |
|
|
|
</el-form> |
|
|
|
|
|
|
|
<!-- 底部 --> |
|
|
|
<div class="el-login-footer"> |
|
|
|
<span></span> |
|
|
|
<!-- 左侧动态背景区域 --> |
|
|
|
<div class="login-left"> |
|
|
|
<!-- 网格背景 --> |
|
|
|
<div class="grid-overlay"></div> |
|
|
|
|
|
|
|
<!-- 地图网格线 SVG --> |
|
|
|
<svg class="map-grid" viewBox="0 0 100 100" preserveAspectRatio="none"> |
|
|
|
<line x1="20" y1="0" x2="20" y2="100" stroke="rgba(76,175,80,0.3)" stroke-width="0.1"/> |
|
|
|
<line x1="40" y1="0" x2="40" y2="100" stroke="rgba(76,175,80,0.3)" stroke-width="0.1"/> |
|
|
|
<line x1="60" y1="0" x2="60" y2="100" stroke="rgba(76,175,80,0.3)" stroke-width="0.1"/> |
|
|
|
<line x1="80" y1="0" x2="80" y2="100" stroke="rgba(76,175,80,0.3)" stroke-width="0.1"/> |
|
|
|
<line x1="0" y1="20" x2="100" y2="20" stroke="rgba(76,175,80,0.3)" stroke-width="0.1"/> |
|
|
|
<line x1="0" y1="40" x2="100" y2="40" stroke="rgba(76,175,80,0.3)" stroke-width="0.1"/> |
|
|
|
<line x1="0" y1="60" x2="100" y2="60" stroke="rgba(76,175,80,0.3)" stroke-width="0.1"/> |
|
|
|
<line x1="0" y1="80" x2="100" y2="80" stroke="rgba(76,175,80,0.3)" stroke-width="0.1"/> |
|
|
|
</svg> |
|
|
|
|
|
|
|
<!-- 地图轮廓 SVG --> |
|
|
|
<svg class="map-contours" viewBox="0 0 800 600" preserveAspectRatio="xMidYMid slice"> |
|
|
|
<path d="M100,100 Q200,50 300,100 T500,100 T700,150" stroke="rgba(255,255,255,0.4)" fill="none" stroke-width="1.5"/> |
|
|
|
<path d="M50,200 Q150,150 250,200 T450,200 T650,250 T750,200" stroke="rgba(255,255,255,0.3)" fill="none" stroke-width="1"/> |
|
|
|
<path d="M100,300 Q250,250 400,300 T700,350" stroke="rgba(255,255,255,0.35)" fill="none" stroke-width="1"/> |
|
|
|
<path d="M50,400 Q200,350 350,400 T550,400 T750,450" stroke="rgba(255,255,255,0.25)" fill="none" stroke-width="1"/> |
|
|
|
<path d="M100,500 Q300,450 500,500 T700,500" stroke="rgba(255,255,255,0.3)" fill="none" stroke-width="1"/> |
|
|
|
<path d="M200,50 Q350,100 500,50 T800,100" stroke="rgba(76,175,80,0.3)" fill="none" stroke-width="1"/> |
|
|
|
<path d="M0,150 Q200,200 400,150 T800,200" stroke="rgba(76,175,80,0.25)" fill="none" stroke-width="1"/> |
|
|
|
</svg> |
|
|
|
|
|
|
|
<!-- 连接线 SVG --> |
|
|
|
<svg class="connection-lines" viewBox="0 0 100 100" preserveAspectRatio="none"> |
|
|
|
<line x1="12" y1="15" x2="50" y2="50" stroke="rgba(76,175,80,0.6)" stroke-width="0.15"/> |
|
|
|
<line x1="78" y1="25" x2="50" y2="50" stroke="rgba(33,150,243,0.6)" stroke-width="0.15"/> |
|
|
|
<line x1="18" y1="55" x2="50" y2="50" stroke="rgba(255,193,7,0.6)" stroke-width="0.15"/> |
|
|
|
<line x1="70" y1="70" x2="50" y2="50" stroke="rgba(76,175,80,0.6)" stroke-width="0.15"/> |
|
|
|
<line x1="88" y1="40" x2="50" y2="50" stroke="rgba(255,87,34,0.6)" stroke-width="0.15"/> |
|
|
|
<line x1="35" y1="82" x2="50" y2="50" stroke="rgba(33,150,243,0.6)" stroke-width="0.15"/> |
|
|
|
<line x1="5" y1="30" x2="50" y2="50" stroke="rgba(156,39,176,0.6)" stroke-width="0.15"/> |
|
|
|
<line x1="85" y1="85" x2="50" y2="50" stroke="rgba(76,175,80,0.6)" stroke-width="0.15"/> |
|
|
|
<line x1="12" y1="15" x2="78" y2="25" stroke="rgba(255,255,255,0.2)" stroke-width="0.05" stroke-dasharray="0.5,0.5"/> |
|
|
|
<line x1="18" y1="55" x2="70" y2="70" stroke="rgba(255,255,255,0.2)" stroke-width="0.05" stroke-dasharray="0.5,0.5"/> |
|
|
|
</svg> |
|
|
|
|
|
|
|
<!-- 十字准星 SVG --> |
|
|
|
<svg class="crosshair" width="600" height="600" viewBox="0 0 200 200"> |
|
|
|
<circle cx="100" cy="100" r="90" fill="none" stroke="rgba(76,175,80,0.2)" stroke-width="1" stroke-dasharray="5,3"/> |
|
|
|
<circle cx="100" cy="100" r="80" fill="none" stroke="rgba(76,175,80,0.15)" stroke-width="0.5"/> |
|
|
|
<line x1="100" y1="20" x2="100" y2="80" stroke="rgba(76,175,80,0.3)" stroke-width="0.5"/> |
|
|
|
<line x1="100" y1="120" x2="100" y2="180" stroke="rgba(76,175,80,0.3)" stroke-width="0.5"/> |
|
|
|
<line x1="20" y1="100" x2="80" y2="100" stroke="rgba(76,175,80,0.3)" stroke-width="0.5"/> |
|
|
|
<line x1="120" y1="100" x2="180" y2="100" stroke="rgba(76,175,80,0.3)" stroke-width="0.5"/> |
|
|
|
<path d="M 30 30 L 30 50 M 30 30 L 50 30" stroke="rgba(76,175,80,0.4)" stroke-width="1" fill="none"/> |
|
|
|
<path d="M 170 30 L 170 50 M 170 30 L 150 30" stroke="rgba(76,175,80,0.4)" stroke-width="1" fill="none"/> |
|
|
|
<path d="M 30 170 L 30 150 M 30 170 L 50 170" stroke="rgba(76,175,80,0.4)" stroke-width="1" fill="none"/> |
|
|
|
<path d="M 170 170 L 170 150 M 170 170 L 150 170" stroke="rgba(76,175,80,0.4)" stroke-width="1" fill="none"/> |
|
|
|
</svg> |
|
|
|
|
|
|
|
<!-- 脉冲波纹 --> |
|
|
|
<div class="ripple"></div> |
|
|
|
<div class="ripple"></div> |
|
|
|
<div class="ripple"></div> |
|
|
|
<div class="ripple"></div> |
|
|
|
|
|
|
|
<!-- 定位点 --> |
|
|
|
<div class="location-pins"> |
|
|
|
<div class="pin"> |
|
|
|
<svg viewBox="0 0 24 24" fill="currentColor"> |
|
|
|
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/> |
|
|
|
</svg> |
|
|
|
</div> |
|
|
|
<div class="pin"> |
|
|
|
<svg viewBox="0 0 24 24" fill="currentColor"> |
|
|
|
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/> |
|
|
|
</svg> |
|
|
|
</div> |
|
|
|
<div class="pin"> |
|
|
|
<svg viewBox="0 0 24 24" fill="currentColor"> |
|
|
|
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/> |
|
|
|
</svg> |
|
|
|
</div> |
|
|
|
<div class="pin"> |
|
|
|
<svg viewBox="0 0 24 24" fill="currentColor"> |
|
|
|
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/> |
|
|
|
</svg> |
|
|
|
</div> |
|
|
|
<div class="pin"> |
|
|
|
<svg viewBox="0 0 24 24" fill="currentColor"> |
|
|
|
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/> |
|
|
|
</svg> |
|
|
|
</div> |
|
|
|
<div class="pin"> |
|
|
|
<svg viewBox="0 0 24 24" fill="currentColor"> |
|
|
|
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/> |
|
|
|
</svg> |
|
|
|
</div> |
|
|
|
<div class="pin"> |
|
|
|
<svg viewBox="0 0 24 24" fill="currentColor"> |
|
|
|
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/> |
|
|
|
</svg> |
|
|
|
</div> |
|
|
|
<div class="pin"> |
|
|
|
<svg viewBox="0 0 24 24" fill="currentColor"> |
|
|
|
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/> |
|
|
|
</svg> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 装饰圆环 --> |
|
|
|
<div class="orbit-ring"></div> |
|
|
|
<div class="orbit-ring"></div> |
|
|
|
<div class="orbit-ring"></div> |
|
|
|
<div class="orbit-ring"></div> |
|
|
|
|
|
|
|
<!-- 粒子效果 --> |
|
|
|
<div class="particles" id="particles"></div> |
|
|
|
|
|
|
|
<!-- 中央超大定位标记 --> |
|
|
|
<div class="center-marker"> |
|
|
|
<svg class="marker-icon" viewBox="0 0 100 100"> |
|
|
|
<circle cx="50" cy="50" r="48" fill="none" stroke="rgba(255,255,255,0.15)" stroke-width="1"/> |
|
|
|
<circle cx="50" cy="50" r="40" fill="none" stroke="rgba(76,175,80,0.2)" stroke-width="1.5"/> |
|
|
|
<path d="M50 10 C32 10 20 24 20 42 C20 65 50 90 50 90 C50 90 80 65 80 42 C80 24 68 10 50 10 Z" |
|
|
|
fill="rgba(76,175,80,0.85)" |
|
|
|
stroke="rgba(255,255,255,0.7)" |
|
|
|
stroke-width="2.5"/> |
|
|
|
<circle cx="50" cy="38" r="12" fill="rgba(255,255,255,0.95)"/> |
|
|
|
<circle cx="50" cy="38" r="7" fill="rgba(76,175,80,1)"/> |
|
|
|
<circle cx="50" cy="38" r="18" fill="none" stroke="rgba(76,175,80,0.6)" stroke-width="2"> |
|
|
|
<animate attributeName="r" from="18" to="35" dur="2s" repeatCount="indefinite"/> |
|
|
|
<animate attributeName="opacity" from="0.6" to="0" dur="2s" repeatCount="indefinite"/> |
|
|
|
</circle> |
|
|
|
<circle cx="50" cy="38" r="18" fill="none" stroke="rgba(76,175,80,0.4)" stroke-width="1.5"> |
|
|
|
<animate attributeName="r" from="18" to="45" dur="2s" begin="0.5s" repeatCount="indefinite"/> |
|
|
|
<animate attributeName="opacity" from="0.4" to="0" dur="2s" begin="0.5s" repeatCount="indefinite"/> |
|
|
|
</circle> |
|
|
|
<circle cx="50" cy="38" r="18" fill="none" stroke="rgba(76,175,80,0.3)" stroke-width="1"> |
|
|
|
<animate attributeName="r" from="18" to="55" dur="2s" begin="1s" repeatCount="indefinite"/> |
|
|
|
<animate attributeName="opacity" from="0.3" to="0" dur="2s" begin="1s" repeatCount="indefinite"/> |
|
|
|
</circle> |
|
|
|
</svg> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 右侧登录表单区域 --> |
|
|
|
<div class="login-right"> |
|
|
|
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form"> |
|
|
|
<h3 class="title">GeoTag 企业客户后台</h3> |
|
|
|
<el-form-item prop="username"> |
|
|
|
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号"> |
|
|
|
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" /> |
|
|
|
</el-input> |
|
|
|
</el-form-item> |
|
|
|
<el-form-item prop="password"> |
|
|
|
<el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码" |
|
|
|
@keyup.enter.native="handleLogin"> |
|
|
|
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" /> |
|
|
|
</el-input> |
|
|
|
</el-form-item> |
|
|
|
<el-form-item prop="code"> |
|
|
|
<el-input v-model="loginForm.code" auto-complete="off" placeholder="谷歌验证码" style="width: 100%" |
|
|
|
@keyup.enter.native="handleLogin"> |
|
|
|
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" /> |
|
|
|
</el-input> |
|
|
|
<!-- <div class="login-code"> |
|
|
|
<img :src="codeUrl" @click="getCode" class="login-code-img"/> |
|
|
|
</div> --> |
|
|
|
</el-form-item> |
|
|
|
<!-- 人机验证 --> |
|
|
|
<!-- <el-form-item prop='validateCode'> |
|
|
|
<el-row :span="24"> |
|
|
|
<el-col :span="24"> |
|
|
|
<reCaptcha :sitekey="key" @getValidateCode='getValidateCode' v-model="loginForm.validateCode"></reCaptcha> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
</el-form-item> --> |
|
|
|
|
|
|
|
<!-- <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox> --> |
|
|
|
<el-form-item style="width:100%;"> |
|
|
|
<el-button :loading="loading" size="medium" type="primary" style="width:100%;" |
|
|
|
@click.native.prevent="handleLogin"> |
|
|
|
<span v-if="!loading">登 录</span> |
|
|
|
<span v-else>登 录 中...</span> |
|
|
|
</el-button> |
|
|
|
</el-form-item> |
|
|
|
</el-form> |
|
|
|
|
|
|
|
<!-- 底部 --> |
|
|
|
<div class="el-login-footer"> |
|
|
|
<span>Copyright © 2026 GeoTag All Rights Reserved</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
@ -92,7 +236,6 @@ export default { |
|
|
|
loading: false, |
|
|
|
redirect: undefined |
|
|
|
}; |
|
|
|
|
|
|
|
}, |
|
|
|
watch: { |
|
|
|
$route: { |
|
|
|
@ -105,7 +248,25 @@ export default { |
|
|
|
created() { |
|
|
|
// this.getCookie(); |
|
|
|
}, |
|
|
|
mounted() { |
|
|
|
this.initParticles(); |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
initParticles() { |
|
|
|
const particlesContainer = document.getElementById('particles'); |
|
|
|
if (particlesContainer) { |
|
|
|
for (let i = 0; i < 40; i++) { |
|
|
|
const particle = document.createElement('div'); |
|
|
|
particle.className = 'particle'; |
|
|
|
particle.style.left = Math.random() * 100 + '%'; |
|
|
|
particle.style.animationDelay = Math.random() * 25 + 's'; |
|
|
|
particle.style.animationDuration = (20 + Math.random() * 10) + 's'; |
|
|
|
particle.style.width = (2 + Math.random() * 3) + 'px'; |
|
|
|
particle.style.height = particle.style.width; |
|
|
|
particlesContainer.appendChild(particle); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
icoCreate(icoUrl) { |
|
|
|
var link = document.querySelector("link[rel*='icon']") || document.createElement('link'); |
|
|
|
link.type = 'image/x-icon'; |
|
|
|
@ -155,25 +316,226 @@ export default { |
|
|
|
<style rel="stylesheet/scss" lang="scss"> |
|
|
|
.login { |
|
|
|
display: flex; |
|
|
|
justify-content: center; |
|
|
|
align-items: center; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
background-image: url("../assets/images/bg.png"); |
|
|
|
background-size: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
/* 左侧动态背景区域 */ |
|
|
|
.login-left { |
|
|
|
flex: 0 0 60%; |
|
|
|
position: relative; |
|
|
|
background: linear-gradient(135deg, #0a1929 0%, #0d3c61 30%, #01579b 60%, #006064 100%); |
|
|
|
overflow: hidden; |
|
|
|
} |
|
|
|
|
|
|
|
/* 网格背景 */ |
|
|
|
.grid-overlay { |
|
|
|
position: absolute; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
background-image: |
|
|
|
linear-gradient(rgba(76,175,80,0.08) 1px, transparent 1px), |
|
|
|
linear-gradient(90deg, rgba(76,175,80,0.08) 1px, transparent 1px); |
|
|
|
background-size: 60px 60px; |
|
|
|
} |
|
|
|
|
|
|
|
/* 地图轮廓 */ |
|
|
|
.map-contours { |
|
|
|
position: absolute; |
|
|
|
top: 50%; |
|
|
|
left: 50%; |
|
|
|
transform: translate(-50%, -50%); |
|
|
|
width: 90%; |
|
|
|
height: 90%; |
|
|
|
opacity: 0.15; |
|
|
|
} |
|
|
|
|
|
|
|
/* 定位点动画 */ |
|
|
|
.location-pins { |
|
|
|
position: absolute; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
.pin { |
|
|
|
position: absolute; |
|
|
|
animation: pulsePin 3s ease-in-out infinite; |
|
|
|
} |
|
|
|
|
|
|
|
.pin svg { |
|
|
|
width: 50px; |
|
|
|
height: 50px; |
|
|
|
filter: drop-shadow(0 0 15px currentColor); |
|
|
|
} |
|
|
|
|
|
|
|
.pin:nth-child(1) { top: 15%; left: 12%; animation-delay: 0s; color: rgba(76,175,80,0.9); } |
|
|
|
.pin:nth-child(2) { top: 25%; left: 78%; animation-delay: 0.5s; color: rgba(33,150,243,0.9); } |
|
|
|
.pin:nth-child(3) { top: 55%; left: 18%; animation-delay: 1s; color: rgba(255,193,7,0.9); } |
|
|
|
.pin:nth-child(4) { top: 70%; left: 70%; animation-delay: 1.5s; color: rgba(76,175,80,0.9); } |
|
|
|
.pin:nth-child(5) { top: 40%; left: 88%; animation-delay: 2s; color: rgba(255,87,34,0.9); } |
|
|
|
.pin:nth-child(6) { top: 82%; left: 35%; animation-delay: 2.5s; color: rgba(33,150,243,0.9); } |
|
|
|
.pin:nth-child(7) { top: 30%; left: 5%; animation-delay: 0.8s; color: rgba(156,39,176,0.9); } |
|
|
|
.pin:nth-child(8) { top: 85%; left: 85%; animation-delay: 1.8s; color: rgba(76,175,80,0.9); } |
|
|
|
|
|
|
|
@keyframes pulsePin { |
|
|
|
0%, 100% { transform: scale(1); opacity: 0.7; } |
|
|
|
50% { transform: scale(1.15); opacity: 1; } |
|
|
|
} |
|
|
|
|
|
|
|
/* 连接线 */ |
|
|
|
.connection-lines { |
|
|
|
position: absolute; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
opacity: 0.2; |
|
|
|
} |
|
|
|
|
|
|
|
/* 中央大定位标记 */ |
|
|
|
.center-marker { |
|
|
|
position: absolute; |
|
|
|
top: 50%; |
|
|
|
left: 50%; |
|
|
|
transform: translate(-50%, -50%); |
|
|
|
text-align: center; |
|
|
|
} |
|
|
|
|
|
|
|
.marker-icon { |
|
|
|
width: 350px; |
|
|
|
height: 350px; |
|
|
|
animation: float 4s ease-in-out infinite; |
|
|
|
} |
|
|
|
|
|
|
|
@keyframes float { |
|
|
|
0%, 100% { transform: translateY(0); } |
|
|
|
50% { transform: translateY(-20px); } |
|
|
|
} |
|
|
|
|
|
|
|
/* 装饰圆环 */ |
|
|
|
.orbit-ring { |
|
|
|
position: absolute; |
|
|
|
top: 50%; |
|
|
|
left: 50%; |
|
|
|
transform: translate(-50%, -50%); |
|
|
|
border: 2px solid rgba(76, 175, 80, 0.15); |
|
|
|
border-radius: 50%; |
|
|
|
animation: rotate 60s linear infinite; |
|
|
|
} |
|
|
|
|
|
|
|
.orbit-ring:nth-child(1) { width: 500px; height: 500px; } |
|
|
|
.orbit-ring:nth-child(2) { width: 700px; height: 700px; animation-duration: 80s; animation-direction: reverse; } |
|
|
|
.orbit-ring:nth-child(3) { width: 900px; height: 900px; animation-duration: 100s; } |
|
|
|
.orbit-ring:nth-child(4) { width: 1100px; height: 1100px; animation-duration: 120s; } |
|
|
|
|
|
|
|
@keyframes rotate { |
|
|
|
from { transform: translate(-50%, -50%) rotate(0deg); } |
|
|
|
to { transform: translate(-50%, -50%) rotate(360deg); } |
|
|
|
} |
|
|
|
|
|
|
|
/* 粒子效果 */ |
|
|
|
.particles { |
|
|
|
position: absolute; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
overflow: hidden; |
|
|
|
} |
|
|
|
|
|
|
|
.particle { |
|
|
|
position: absolute; |
|
|
|
width: 3px; |
|
|
|
height: 3px; |
|
|
|
background: rgba(76, 175, 80, 0.5); |
|
|
|
border-radius: 50%; |
|
|
|
animation: particleFloat 25s linear infinite; |
|
|
|
} |
|
|
|
|
|
|
|
@keyframes particleFloat { |
|
|
|
0% { transform: translateY(100vh) rotate(0deg); opacity: 0; } |
|
|
|
10% { opacity: 1; } |
|
|
|
90% { opacity: 1; } |
|
|
|
100% { transform: translateY(-100vh) rotate(720deg); opacity: 0; } |
|
|
|
} |
|
|
|
|
|
|
|
/* 十字准星 */ |
|
|
|
.crosshair { |
|
|
|
position: absolute; |
|
|
|
top: 50%; |
|
|
|
left: 50%; |
|
|
|
transform: translate(-50%, -50%); |
|
|
|
pointer-events: none; |
|
|
|
} |
|
|
|
|
|
|
|
/* 地图网格线 */ |
|
|
|
.map-grid { |
|
|
|
position: absolute; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
opacity: 0.1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 脉冲波纹 */ |
|
|
|
.ripple { |
|
|
|
position: absolute; |
|
|
|
top: 50%; |
|
|
|
left: 50%; |
|
|
|
transform: translate(-50%, -50%); |
|
|
|
border: 2px solid rgba(76, 175, 80, 0.3); |
|
|
|
border-radius: 50%; |
|
|
|
animation: rippleEffect 4s ease-out infinite; |
|
|
|
} |
|
|
|
|
|
|
|
.ripple:nth-child(1) { animation-delay: 0s; } |
|
|
|
.ripple:nth-child(2) { animation-delay: 1s; } |
|
|
|
.ripple:nth-child(3) { animation-delay: 2s; } |
|
|
|
.ripple:nth-child(4) { animation-delay: 3s; } |
|
|
|
|
|
|
|
@keyframes rippleEffect { |
|
|
|
0% { |
|
|
|
width: 100px; |
|
|
|
height: 100px; |
|
|
|
opacity: 0.8; |
|
|
|
} |
|
|
|
100% { |
|
|
|
width: 800px; |
|
|
|
height: 800px; |
|
|
|
opacity: 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 右侧登录表单区域 */ |
|
|
|
.login-right { |
|
|
|
flex: 0 0 40%; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
justify-content: center; |
|
|
|
align-items: center; |
|
|
|
background: linear-gradient(135deg, #f5f7fa 0%, #e8eef5 100%); |
|
|
|
position: relative; |
|
|
|
} |
|
|
|
|
|
|
|
.title { |
|
|
|
margin: 0px auto 30px auto; |
|
|
|
text-align: center; |
|
|
|
color: #0A1146; |
|
|
|
font-size: 26px; |
|
|
|
font-weight: 600; |
|
|
|
} |
|
|
|
|
|
|
|
.login-form { |
|
|
|
border-radius: 6px; |
|
|
|
border-radius: 8px; |
|
|
|
background: #ffffff; |
|
|
|
width: 400px; |
|
|
|
padding: 25px 25px 5px 25px; |
|
|
|
padding: 40px 35px 15px 35px; |
|
|
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); |
|
|
|
|
|
|
|
.el-input { |
|
|
|
height: 38px; |
|
|
|
@ -210,11 +572,11 @@ export default { |
|
|
|
.el-login-footer { |
|
|
|
height: 40px; |
|
|
|
line-height: 40px; |
|
|
|
position: fixed; |
|
|
|
position: absolute; |
|
|
|
bottom: 0; |
|
|
|
width: 100%; |
|
|
|
text-align: center; |
|
|
|
color: #fff; |
|
|
|
color: #999; |
|
|
|
font-family: Arial; |
|
|
|
font-size: 12px; |
|
|
|
letter-spacing: 1px; |
|
|
|
@ -223,4 +585,30 @@ export default { |
|
|
|
.login-code-img { |
|
|
|
height: 38px; |
|
|
|
} |
|
|
|
</style> |
|
|
|
|
|
|
|
/* 响应式 */ |
|
|
|
@media (max-width: 1024px) { |
|
|
|
.login-left { |
|
|
|
flex: 0 0 50%; |
|
|
|
} |
|
|
|
.login-right { |
|
|
|
flex: 0 0 50%; |
|
|
|
} |
|
|
|
.login-form { |
|
|
|
width: 350px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@media (max-width: 768px) { |
|
|
|
.login-left { |
|
|
|
display: none; |
|
|
|
} |
|
|
|
.login-right { |
|
|
|
flex: 0 0 100%; |
|
|
|
} |
|
|
|
.login-form { |
|
|
|
width: 90%; |
|
|
|
max-width: 400px; |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |