|
|
@@ -1,44 +1,272 @@
|
|
|
<template>
|
|
|
- <div class="login-container">
|
|
|
- <el-card class="login-card">
|
|
|
- <h2 class="title">浠艾福管理后台</h2>
|
|
|
- <el-form :model="loginForm" :rules="rules" ref="loginForm">
|
|
|
- <el-form-item prop="username">
|
|
|
- <el-input
|
|
|
- v-model="loginForm.username"
|
|
|
- placeholder="请输入用户名"
|
|
|
- prefix-icon="el-icon-user"
|
|
|
- ></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item prop="password">
|
|
|
- <el-input
|
|
|
- v-model="loginForm.password"
|
|
|
- type="password"
|
|
|
- placeholder="请输入密码"
|
|
|
- prefix-icon="el-icon-lock"
|
|
|
- @keyup.enter.native="handleLogin"
|
|
|
- ></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item>
|
|
|
- <el-button
|
|
|
- type="primary"
|
|
|
- class="login-btn"
|
|
|
- @click="handleLogin"
|
|
|
- :loading="loading"
|
|
|
- >
|
|
|
- 登录
|
|
|
- </el-button>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
- </el-card>
|
|
|
+ <div class="login-page">
|
|
|
+ <!-- 左侧品牌展示区 — 五行相生相克沙盘 -->
|
|
|
+ <div class="brand-panel">
|
|
|
+ <div class="brand-content">
|
|
|
+
|
|
|
+ <!-- ===== 五维能量沙盘 · 相生相克图 ===== -->
|
|
|
+ <div class="sand-table-wrap">
|
|
|
+ <svg class="sand-table-svg" viewBox="0 0 340 370" xmlns="http://www.w3.org/2000/svg">
|
|
|
+ <defs>
|
|
|
+ <!-- 相生箭头(userSpaceOnUse 精确定位,箭头尖在圆边) -->
|
|
|
+ <marker id="arrowGen" markerWidth="52" markerHeight="10" refX="48" refY="5" orient="auto" markerUnits="userSpaceOnUse">
|
|
|
+ <polygon points="7,5 0,0 0,10" fill="#FFE066" />
|
|
|
+ </marker>
|
|
|
+ <!-- 相克箭头 -->
|
|
|
+ <marker id="arrowOve" markerWidth="45" markerHeight="12" refX="41" refY="6" orient="auto" markerUnits="userSpaceOnUse">
|
|
|
+ <polygon points="7,6 0,0 0,12" fill="#FF8A80" />
|
|
|
+ </marker>
|
|
|
+
|
|
|
+ <!-- 节点径向渐变 -->
|
|
|
+ <radialGradient id="gradEarth" cx="40%" cy="35%" r="60%">
|
|
|
+ <stop offset="0%" stop-color="#D4B896" />
|
|
|
+ <stop offset="100%" stop-color="#9A7B4F" />
|
|
|
+ </radialGradient>
|
|
|
+ <radialGradient id="gradMetal" cx="40%" cy="35%" r="60%">
|
|
|
+ <stop offset="0%" stop-color="#F0DA70" />
|
|
|
+ <stop offset="100%" stop-color="#D4A843" />
|
|
|
+ </radialGradient>
|
|
|
+ <radialGradient id="gradWater" cx="40%" cy="35%" r="60%">
|
|
|
+ <stop offset="0%" stop-color="#8FC5E8" />
|
|
|
+ <stop offset="100%" stop-color="#5B9BD5" />
|
|
|
+ </radialGradient>
|
|
|
+ <radialGradient id="gradWood" cx="40%" cy="35%" r="60%">
|
|
|
+ <stop offset="0%" stop-color="#81C784" />
|
|
|
+ <stop offset="100%" stop-color="#4CAF50" />
|
|
|
+ </radialGradient>
|
|
|
+ <radialGradient id="gradFire" cx="40%" cy="35%" r="60%">
|
|
|
+ <stop offset="0%" stop-color="#FFAB91" />
|
|
|
+ <stop offset="100%" stop-color="#F08A7A" />
|
|
|
+ </radialGradient>
|
|
|
+
|
|
|
+ <!-- 外环渐变轨道 -->
|
|
|
+ <linearGradient id="ringGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
|
+ <stop offset="0%" stop-color="#FFD700" stop-opacity="0.25" />
|
|
|
+ <stop offset="25%" stop-color="#FFE066" stop-opacity="0.15" />
|
|
|
+ <stop offset="50%" stop-color="#FFD700" stop-opacity="0.08" />
|
|
|
+ <stop offset="75%" stop-color="#FFE066" stop-opacity="0.15" />
|
|
|
+ <stop offset="100%" stop-color="#FFD700" stop-opacity="0.25" />
|
|
|
+ </linearGradient>
|
|
|
+
|
|
|
+ <!-- 发光滤镜 -->
|
|
|
+ <filter id="glowStrong">
|
|
|
+ <feGaussianBlur stdDeviation="4" result="blur"/>
|
|
|
+ <feMerge>
|
|
|
+ <feMergeNode in="blur"/>
|
|
|
+ <feMergeNode in="blur"/>
|
|
|
+ <feMergeNode in="SourceGraphic"/>
|
|
|
+ </feMerge>
|
|
|
+ </filter>
|
|
|
+ <filter id="glowNode">
|
|
|
+ <feGaussianBlur stdDeviation="2.5" result="blur"/>
|
|
|
+ <feMerge>
|
|
|
+ <feMergeNode in="blur"/>
|
|
|
+ <feMergeNode in="blur"/>
|
|
|
+ <feMergeNode in="SourceGraphic"/>
|
|
|
+ </feMerge>
|
|
|
+ </filter>
|
|
|
+ </defs>
|
|
|
+
|
|
|
+ <!-- 背景光晕 -->
|
|
|
+ <circle cx="170" cy="190" r="140" fill="url(#ringGrad)" />
|
|
|
+
|
|
|
+ <!-- 外层装饰轨道 -->
|
|
|
+ <circle cx="170" cy="190" r="132" fill="none" stroke="rgba(255,255,255,0.06)" stroke-width="1" />
|
|
|
+ <circle cx="170" cy="190" r="129" fill="none" stroke="rgba(255,215,0,0.10)" stroke-width="0.5" stroke-dasharray="2,4" class="orbital-ring" />
|
|
|
+
|
|
|
+ <!-- 轨道粒子 -->
|
|
|
+ <circle cx="170" cy="58" r="2" fill="#FFE066" opacity="0.5" class="particle" />
|
|
|
+ <circle cx="271" cy="133" r="2" fill="#FFE066" opacity="0.5" class="particle" />
|
|
|
+ <circle cx="240" cy="280" r="2" fill="#FFE066" opacity="0.5" class="particle" />
|
|
|
+ <circle cx="100" cy="280" r="2" fill="#FFE066" opacity="0.5" class="particle" />
|
|
|
+ <circle cx="69" cy="133" r="2" fill="#FFE066" opacity="0.5" class="particle" />
|
|
|
+
|
|
|
+ <!-- ===== 相生环 ===== -->
|
|
|
+ <!-- 土→金 -->
|
|
|
+ <path d="M 170,85 A 105,105 0 0,1 270,158" fill="none" stroke="#FFD700" stroke-width="2.5" stroke-opacity="0.8" class="arc-gen" marker-end="url(#arrowGen)" />
|
|
|
+ <!-- 金→水 -->
|
|
|
+ <path d="M 270,158 A 105,105 0 0,1 232,275" fill="none" stroke="#FFD700" stroke-width="2.5" stroke-opacity="0.8" class="arc-gen" marker-end="url(#arrowGen)" />
|
|
|
+ <!-- 水→木 -->
|
|
|
+ <path d="M 232,275 A 105,105 0 0,1 108,275" fill="none" stroke="#FFD700" stroke-width="2.5" stroke-opacity="0.8" class="arc-gen" marker-end="url(#arrowGen)" />
|
|
|
+ <!-- 木→火 -->
|
|
|
+ <path d="M 108,275 A 105,105 0 0,1 70,158" fill="none" stroke="#FFD700" stroke-width="2.5" stroke-opacity="0.8" class="arc-gen" marker-end="url(#arrowGen)" />
|
|
|
+ <!-- 火→土 -->
|
|
|
+ <path d="M 70,158 A 105,105 0 0,1 170,85" fill="none" stroke="#FFD700" stroke-width="2.5" stroke-opacity="0.8" class="arc-gen" marker-end="url(#arrowGen)" />
|
|
|
+
|
|
|
+ <!-- ===== 相克线(内五角星) ===== -->
|
|
|
+ <!-- 木克土 行→身(静态线,无脉冲闪烁) -->
|
|
|
+ <line x1="108" y1="275" x2="170" y2="85" stroke="#FF8A80" stroke-width="1.5" stroke-dasharray="6,6" stroke-opacity="0.45" class="line-ove-quiet" marker-end="url(#arrowOve)" />
|
|
|
+ <!-- 土克水 身→富 -->
|
|
|
+ <line x1="170" y1="85" x2="232" y2="275" stroke="#FF8A80" stroke-width="2" stroke-dasharray="6,6" class="line-ove" marker-end="url(#arrowOve)" />
|
|
|
+ <!-- 水克火 富→心 -->
|
|
|
+ <line x1="232" y1="275" x2="70" y2="158" stroke="#FF8A80" stroke-width="2" stroke-dasharray="6,6" class="line-ove" marker-end="url(#arrowOve)" />
|
|
|
+ <!-- 火克金 心→智 -->
|
|
|
+ <line x1="70" y1="158" x2="270" y2="158" stroke="#FF8A80" stroke-width="2" stroke-dasharray="6,6" class="line-ove" marker-end="url(#arrowOve)" />
|
|
|
+ <!-- 金克木 智→行 -->
|
|
|
+ <line x1="270" y1="158" x2="108" y2="275" stroke="#FF8A80" stroke-width="2" stroke-dasharray="6,6" class="line-ove" marker-end="url(#arrowOve)" />
|
|
|
+
|
|
|
+ <!-- ===== 五维节点 ===== -->
|
|
|
+
|
|
|
+ <!-- 身(土) — 上 -->
|
|
|
+ <g class="node-group">
|
|
|
+ <circle cx="170" cy="85" r="34" fill="url(#gradEarth)" stroke="rgba(212,184,150,0.5)" stroke-width="2" filter="url(#glowNode)" />
|
|
|
+ <circle cx="170" cy="85" r="30" fill="none" stroke="rgba(255,255,255,0.08)" stroke-width="0.5" />
|
|
|
+ <text x="170" y="79" text-anchor="middle" fill="#fff" font-size="18">🌏</text>
|
|
|
+ <text x="170" y="100" text-anchor="middle" fill="#fff" font-size="15" font-weight="600">身</text>
|
|
|
+ <text x="170" y="114" text-anchor="middle" fill="rgba(255,255,255,0.45)" font-size="9">土</text>
|
|
|
+ </g>
|
|
|
+
|
|
|
+ <!-- 智(金) — 右上 -->
|
|
|
+ <g class="node-group">
|
|
|
+ <circle cx="270" cy="158" r="34" fill="url(#gradMetal)" stroke="rgba(240,218,112,0.5)" stroke-width="2" filter="url(#glowNode)" />
|
|
|
+ <circle cx="270" cy="158" r="30" fill="none" stroke="rgba(255,255,255,0.08)" stroke-width="0.5" />
|
|
|
+ <text x="270" y="152" text-anchor="middle" fill="#fff" font-size="18">⚔️</text>
|
|
|
+ <text x="270" y="173" text-anchor="middle" fill="#fff" font-size="15" font-weight="600">智</text>
|
|
|
+ <text x="270" y="187" text-anchor="middle" fill="rgba(255,255,255,0.45)" font-size="9">金</text>
|
|
|
+ </g>
|
|
|
+
|
|
|
+ <!-- 富(水) — 右下 -->
|
|
|
+ <g class="node-group">
|
|
|
+ <circle cx="232" cy="275" r="34" fill="url(#gradWater)" stroke="rgba(143,197,232,0.5)" stroke-width="2" filter="url(#glowNode)" />
|
|
|
+ <circle cx="232" cy="275" r="30" fill="none" stroke="rgba(255,255,255,0.08)" stroke-width="0.5" />
|
|
|
+ <text x="232" y="269" text-anchor="middle" fill="#fff" font-size="18">💧</text>
|
|
|
+ <text x="232" y="290" text-anchor="middle" fill="#fff" font-size="15" font-weight="600">富</text>
|
|
|
+ <text x="232" y="304" text-anchor="middle" fill="rgba(255,255,255,0.45)" font-size="9">水</text>
|
|
|
+ </g>
|
|
|
+
|
|
|
+ <!-- 行(木) — 左下 -->
|
|
|
+ <g class="node-group">
|
|
|
+ <circle cx="108" cy="275" r="34" fill="url(#gradWood)" stroke="rgba(129,199,132,0.5)" stroke-width="2" filter="url(#glowNode)" />
|
|
|
+ <circle cx="108" cy="275" r="30" fill="none" stroke="rgba(255,255,255,0.08)" stroke-width="0.5" />
|
|
|
+ <text x="108" y="269" text-anchor="middle" fill="#fff" font-size="18">🌿</text>
|
|
|
+ <text x="108" y="290" text-anchor="middle" fill="#fff" font-size="15" font-weight="600">行</text>
|
|
|
+ <text x="108" y="304" text-anchor="middle" fill="rgba(255,255,255,0.45)" font-size="9">木</text>
|
|
|
+ </g>
|
|
|
+
|
|
|
+ <!-- 心(火) — 左上 -->
|
|
|
+ <g class="node-group">
|
|
|
+ <circle cx="70" cy="158" r="34" fill="url(#gradFire)" stroke="rgba(255,171,145,0.5)" stroke-width="2" filter="url(#glowNode)" />
|
|
|
+ <circle cx="70" cy="158" r="30" fill="none" stroke="rgba(255,255,255,0.08)" stroke-width="0.5" />
|
|
|
+ <text x="70" y="152" text-anchor="middle" fill="#fff" font-size="18">🔥</text>
|
|
|
+ <text x="70" y="173" text-anchor="middle" fill="#fff" font-size="15" font-weight="600">心</text>
|
|
|
+ <text x="70" y="187" text-anchor="middle" fill="rgba(255,255,255,0.45)" font-size="9">火</text>
|
|
|
+ </g>
|
|
|
+
|
|
|
+ <!-- 中心五行文字 -->
|
|
|
+ <text x="170" y="188" text-anchor="middle" fill="rgba(255,255,255,0.07)" font-size="13" letter-spacing="5">五行 · 相生相克</text>
|
|
|
+
|
|
|
+ <!-- 图例 -->
|
|
|
+ <g transform="translate(170, 345)">
|
|
|
+ <line x1="-50" y1="0" x2="-22" y2="0" stroke="#FFD700" stroke-width="2" />
|
|
|
+ <polygon points="-22,0 -17,-3 -17,3" fill="#FFD700" />
|
|
|
+ <text x="-8" y="4" text-anchor="start" fill="rgba(255,255,255,0.5)" font-size="9">相生</text>
|
|
|
+ <line x1="44" y1="0" x2="72" y2="0" stroke="#FF8A80" stroke-width="1.5" stroke-dasharray="4,3" />
|
|
|
+ <polygon points="72,0 77,-3 77,3" fill="#FF8A80" />
|
|
|
+ <text x="80" y="4" text-anchor="start" fill="rgba(255,255,255,0.5)" font-size="9">相克</text>
|
|
|
+ </g>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Logo + 品牌 -->
|
|
|
+ <div class="brand-mid">
|
|
|
+ <div class="brand-logo-row">
|
|
|
+ <img src="/logo.png" alt="浠艾福" class="logo-img" />
|
|
|
+ <span class="brand-name">浠艾福</span>
|
|
|
+ <span class="brand-en">Care Family</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 底部 -->
|
|
|
+ <div class="brand-bottom">
|
|
|
+ <p class="tagline">给全家的一站式幸福提案</p>
|
|
|
+ <div class="role-tags">
|
|
|
+ <span class="role-tag" style="border-color:#5B9BD5">家长</span>
|
|
|
+ <span class="role-tag" style="border-color:#F08A7A">服务商</span>
|
|
|
+ <span class="role-tag" style="border-color:#4CAF50">运营</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 右侧登录表单区 -->
|
|
|
+ <div class="form-panel">
|
|
|
+ <div class="form-card">
|
|
|
+ <div class="form-header">
|
|
|
+ <div class="header-icon">
|
|
|
+ <i class="el-icon-user"></i>
|
|
|
+ </div>
|
|
|
+ <h2 class="form-title">管理后台登录</h2>
|
|
|
+ <p class="form-desc">请使用管理员或规划师账号登录</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-form
|
|
|
+ :model="loginForm"
|
|
|
+ :rules="rules"
|
|
|
+ ref="loginForm"
|
|
|
+ class="login-form"
|
|
|
+ @submit.native.prevent="handleLogin"
|
|
|
+ >
|
|
|
+ <el-form-item prop="username">
|
|
|
+ <el-input
|
|
|
+ v-model="loginForm.username"
|
|
|
+ placeholder="请输入用户名 / 手机号"
|
|
|
+ size="large"
|
|
|
+ :disabled="loading"
|
|
|
+ >
|
|
|
+ <i slot="prefix" class="el-icon-user input-icon"></i>
|
|
|
+ </el-input>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item prop="password">
|
|
|
+ <el-input
|
|
|
+ v-model="loginForm.password"
|
|
|
+ type="password"
|
|
|
+ placeholder="请输入密码"
|
|
|
+ size="large"
|
|
|
+ :disabled="loading"
|
|
|
+ show-password
|
|
|
+ >
|
|
|
+ <i slot="prefix" class="el-icon-lock input-icon"></i>
|
|
|
+ </el-input>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item prop="captcha" class="captcha-item">
|
|
|
+ <SliderCaptcha
|
|
|
+ ref="sliderCaptcha"
|
|
|
+ @success="onCaptchaSuccess"
|
|
|
+ @fail="onCaptchaFail"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item>
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ class="login-btn"
|
|
|
+ @click="handleLogin"
|
|
|
+ :loading="loading"
|
|
|
+ :disabled="!captchaPassed"
|
|
|
+ >
|
|
|
+ {{ loading ? '登录中...' : '登 录' }}
|
|
|
+ </el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <div class="form-footer">
|
|
|
+ <span class="copyright">© 2026 亿图腾(北京)科技有限公司</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import { adminLogin } from '@/api/auth'
|
|
|
+import SliderCaptcha from '@/components/SliderCaptcha'
|
|
|
|
|
|
export default {
|
|
|
name: 'Login',
|
|
|
+ components: { SliderCaptcha },
|
|
|
data() {
|
|
|
return {
|
|
|
loginForm: {
|
|
|
@@ -47,39 +275,55 @@ export default {
|
|
|
},
|
|
|
rules: {
|
|
|
username: [
|
|
|
- { required: true, message: '请输入用户名', trigger: 'blur' }
|
|
|
+ { required: true, message: '请输入用户名', trigger: 'blur' },
|
|
|
+ { min: 2, message: '用户名至少2个字符', trigger: 'blur' }
|
|
|
],
|
|
|
password: [
|
|
|
- { required: true, message: '请输入密码', trigger: 'blur' }
|
|
|
+ { required: true, message: '请输入密码', trigger: 'blur' },
|
|
|
+ { min: 4, message: '密码至少4个字符', trigger: 'blur' }
|
|
|
]
|
|
|
},
|
|
|
- loading: false
|
|
|
+ loading: false,
|
|
|
+ captchaPassed: false
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
+ onCaptchaSuccess() {
|
|
|
+ this.captchaPassed = true
|
|
|
+ },
|
|
|
+ onCaptchaFail() {
|
|
|
+ this.captchaPassed = false
|
|
|
+ },
|
|
|
+ resetCaptcha() {
|
|
|
+ if (this.$refs.sliderCaptcha) this.$refs.sliderCaptcha.reset()
|
|
|
+ this.captchaPassed = false
|
|
|
+ },
|
|
|
handleLogin() {
|
|
|
- this.$refs.loginForm.validate(async valid => {
|
|
|
- if (valid) {
|
|
|
- this.loading = true
|
|
|
- try {
|
|
|
- const res = await adminLogin({
|
|
|
- phone: this.loginForm.username,
|
|
|
- password: this.loginForm.password
|
|
|
- })
|
|
|
- localStorage.setItem('token', res.data.token)
|
|
|
- localStorage.setItem('adminId', res.data.adminId)
|
|
|
- localStorage.setItem('adminName', res.data.realName)
|
|
|
- const role = res.data.role || 'admin'
|
|
|
- localStorage.setItem('role', role)
|
|
|
- console.log('Login successful, role:', role)
|
|
|
- this.$message.success('登录成功,角色:' + role)
|
|
|
- await this.$nextTick()
|
|
|
- this.$router.push({ path: '/' }, () => {})
|
|
|
- } catch (e) {
|
|
|
- this.$message.error(e.message || '登录失败')
|
|
|
- } finally {
|
|
|
- this.loading = false
|
|
|
- }
|
|
|
+ if (!this.captchaPassed) {
|
|
|
+ this.$message.warning('请先完成滑动验证')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.$refs.loginForm.validate(async (valid) => {
|
|
|
+ if (!valid) return
|
|
|
+ this.loading = true
|
|
|
+ try {
|
|
|
+ const res = await adminLogin({
|
|
|
+ phone: this.loginForm.username,
|
|
|
+ password: this.loginForm.password
|
|
|
+ })
|
|
|
+ localStorage.setItem('token', res.data.token)
|
|
|
+ localStorage.setItem('adminId', res.data.adminId)
|
|
|
+ localStorage.setItem('adminName', res.data.realName)
|
|
|
+ const role = res.data.role || 'admin'
|
|
|
+ localStorage.setItem('role', role)
|
|
|
+ this.$message.success('登录成功')
|
|
|
+ await this.$nextTick()
|
|
|
+ this.$router.push({ path: '/' })
|
|
|
+ } catch (e) {
|
|
|
+ this.$message.error(e.message || '登录失败,请检查账号密码')
|
|
|
+ this.resetCaptcha()
|
|
|
+ } finally {
|
|
|
+ this.loading = false
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
@@ -88,26 +332,348 @@ export default {
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-.login-container {
|
|
|
+/* ============================================================
|
|
|
+ 登录页面 — 浠艾福 (Care Family)
|
|
|
+ 品牌色: #5B9BD5 / #F08A7A
|
|
|
+ 五维序: 身(土)→智(金)→富(水)→行(木)→心(火)
|
|
|
+ ============================================================ */
|
|
|
+
|
|
|
+.login-page {
|
|
|
+ display: flex;
|
|
|
+ height: 100vh;
|
|
|
+ width: 100vw;
|
|
|
+ overflow: hidden;
|
|
|
+ font-family: 'Helvetica Neue', Helvetica, 'PingFang SC',
|
|
|
+ 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
|
|
|
+}
|
|
|
+
|
|
|
+/* ==================== 左侧品牌区 ==================== */
|
|
|
+.brand-panel {
|
|
|
+ flex: 0 0 55%;
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background: linear-gradient(165deg, #3A7CC4 0%, #5B9BD5 30%, #6BA8DE 60%, #7BBDE0 100%);
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.brand-content {
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
justify-content: center;
|
|
|
+ max-width: 480px;
|
|
|
+ width: 100%;
|
|
|
+ padding: 16px 40px;
|
|
|
+ color: #fff;
|
|
|
+ min-height: 100vh;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+/* -------- 五维能量沙盘 -------- */
|
|
|
+.sand-table-wrap {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
align-items: center;
|
|
|
- height: 100vh;
|
|
|
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
+ justify-content: center;
|
|
|
+ width: 100%;
|
|
|
+ min-height: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.sand-table-svg {
|
|
|
+ width: 100%;
|
|
|
+ max-width: 340px;
|
|
|
+ height: auto;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+/* ===== 相生环 · 连续流动 ===== */
|
|
|
+.sand-table-svg .arc-gen {
|
|
|
+ stroke-dasharray: 10 8;
|
|
|
+ animation: flowArc 1.2s linear infinite;
|
|
|
+}
|
|
|
+.sand-table-svg .arc-gen:nth-child(4) { animation-delay: 0.00s; }
|
|
|
+.sand-table-svg .arc-gen:nth-child(5) { animation-delay: 0.24s; }
|
|
|
+.sand-table-svg .arc-gen:nth-child(6) { animation-delay: 0.48s; }
|
|
|
+.sand-table-svg .arc-gen:nth-child(7) { animation-delay: 0.72s; }
|
|
|
+.sand-table-svg .arc-gen:nth-child(8) { animation-delay: 0.96s; }
|
|
|
+
|
|
|
+@keyframes flowArc {
|
|
|
+ 0% { stroke-dashoffset: 0; }
|
|
|
+ 100% { stroke-dashoffset: -18; }
|
|
|
+}
|
|
|
+
|
|
|
+/* ===== 相克线 · 脉冲 ===== */
|
|
|
+.sand-table-svg .line-ove {
|
|
|
+ animation: pulseLine 2.2s ease-in-out infinite;
|
|
|
+}
|
|
|
+.sand-table-svg .line-ove:nth-child(10) { animation-delay: 0.00s; }
|
|
|
+.sand-table-svg .line-ove:nth-child(11) { animation-delay: 0.44s; }
|
|
|
+.sand-table-svg .line-ove:nth-child(12) { animation-delay: 0.88s; }
|
|
|
+.sand-table-svg .line-ove:nth-child(13) { animation-delay: 1.32s; }
|
|
|
+
|
|
|
+@keyframes pulseLine {
|
|
|
+ 0%, 100% { stroke-opacity: 0.35; stroke-width: 1.5; }
|
|
|
+ 50% { stroke-opacity: 0.75; stroke-width: 2.5; }
|
|
|
+}
|
|
|
+
|
|
|
+/* 木→土线(静态,无脉冲) */
|
|
|
+.sand-table-svg .line-ove-quiet {
|
|
|
+ stroke-opacity: 0.35;
|
|
|
+}
|
|
|
+
|
|
|
+/* ===== 节点呼吸 ===== */
|
|
|
+.sand-table-svg .node-group {
|
|
|
+ animation: nodeBreathe 3.2s ease-in-out infinite;
|
|
|
+}
|
|
|
+.sand-table-svg .node-group:nth-child(14) { animation-delay: 0.0s; }
|
|
|
+.sand-table-svg .node-group:nth-child(15) { animation-delay: 0.64s; }
|
|
|
+.sand-table-svg .node-group:nth-child(16) { animation-delay: 1.28s; }
|
|
|
+.sand-table-svg .node-group:nth-child(17) { animation-delay: 1.92s; }
|
|
|
+.sand-table-svg .node-group:nth-child(18) { animation-delay: 2.56s; }
|
|
|
+
|
|
|
+@keyframes nodeBreathe {
|
|
|
+ 0%, 100% { opacity: 0.85; transform: scale(1); }
|
|
|
+ 50% { opacity: 1; transform: scale(1.03); }
|
|
|
+}
|
|
|
+
|
|
|
+/* ===== 轨道粒子公转 ===== */
|
|
|
+.sand-table-svg .particle {
|
|
|
+ animation: orbitParticle 8s linear infinite;
|
|
|
+ transform-origin: 170px 190px;
|
|
|
+}
|
|
|
+.sand-table-svg .particle:nth-child(3) { animation-delay: 0.0s; }
|
|
|
+
|
|
|
+@keyframes orbitParticle {
|
|
|
+ 0% { opacity: 0; transform: rotate(0deg) translateX(132px) rotate(0deg); }
|
|
|
+ 12% { opacity: 0.6; }
|
|
|
+ 88% { opacity: 0.6; }
|
|
|
+ 100% { opacity: 0; transform: rotate(360deg) translateX(132px) rotate(-360deg); }
|
|
|
+}
|
|
|
+
|
|
|
+/* -------- Logo + 品牌 -------- */
|
|
|
+.brand-mid {
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin: 6px 0 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.brand-logo-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.logo-img {
|
|
|
+ width: 36px;
|
|
|
+ height: 36px;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+.brand-name {
|
|
|
+ font-size: 22px;
|
|
|
+ font-weight: 700;
|
|
|
+ letter-spacing: 3px;
|
|
|
+ text-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
|
+}
|
|
|
+
|
|
|
+.brand-en {
|
|
|
+ font-size: 11px;
|
|
|
+ opacity: 0.6;
|
|
|
+ letter-spacing: 2px;
|
|
|
+ font-weight: 300;
|
|
|
+ margin-left: -2px;
|
|
|
+}
|
|
|
+
|
|
|
+/* -------- 底部 -------- */
|
|
|
+.brand-bottom {
|
|
|
+ flex-shrink: 0;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.tagline {
|
|
|
+ font-size: 13px;
|
|
|
+ opacity: 0.65;
|
|
|
+ letter-spacing: 2px;
|
|
|
+ font-weight: 300;
|
|
|
+ margin: 0 0 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.role-tags {
|
|
|
+ display: flex;
|
|
|
+ gap: 8px;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.role-tag {
|
|
|
+ display: inline-block;
|
|
|
+ padding: 2px 12px;
|
|
|
+ font-size: 11px;
|
|
|
+ border: 1px solid;
|
|
|
+ border-radius: 20px;
|
|
|
+ opacity: 0.45;
|
|
|
+ transition: opacity 0.3s;
|
|
|
}
|
|
|
|
|
|
-.login-card {
|
|
|
- width: 400px;
|
|
|
- padding: 20px;
|
|
|
+.role-tag:hover {
|
|
|
+ opacity: 0.85;
|
|
|
}
|
|
|
|
|
|
-.title {
|
|
|
+/* ==================== 右侧表单区 ==================== */
|
|
|
+.form-panel {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background: #F5F9FC;
|
|
|
+ padding: 40px;
|
|
|
+}
|
|
|
+
|
|
|
+.form-card {
|
|
|
+ width: 100%;
|
|
|
+ max-width: 400px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 16px;
|
|
|
+ padding: 40px 36px 32px;
|
|
|
+ box-shadow: 0 8px 40px rgba(91, 155, 213, 0.08),
|
|
|
+ 0 1px 4px rgba(0, 0, 0, 0.04);
|
|
|
+}
|
|
|
+
|
|
|
+.form-header {
|
|
|
text-align: center;
|
|
|
- color: #333;
|
|
|
- margin-bottom: 30px;
|
|
|
+ margin-bottom: 32px;
|
|
|
+}
|
|
|
+
|
|
|
+.header-icon {
|
|
|
+ width: 48px;
|
|
|
+ height: 48px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: linear-gradient(135deg, #D6EAF8, #8FC5E8);
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.header-icon i {
|
|
|
+ font-size: 24px;
|
|
|
+ color: #3A7CC4;
|
|
|
+}
|
|
|
+
|
|
|
+.form-title {
|
|
|
+ font-size: 22px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1E293B;
|
|
|
+ margin: 0 0 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.form-desc {
|
|
|
+ font-size: 13px;
|
|
|
+ color: #94A3B8;
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.login-form {
|
|
|
+ margin-bottom: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.login-form >>> .el-input__inner {
|
|
|
+ height: 44px;
|
|
|
+ line-height: 44px;
|
|
|
+ border-radius: 10px;
|
|
|
+ border-color: #E2E8F0;
|
|
|
+ background: #F8FAFC;
|
|
|
+ transition: all 0.25s;
|
|
|
+ font-size: 14px;
|
|
|
+ padding-left: 42px;
|
|
|
+}
|
|
|
+
|
|
|
+.login-form >>> .el-input__inner:focus {
|
|
|
+ border-color: #5B9BD5;
|
|
|
+ background: #fff;
|
|
|
+ box-shadow: 0 0 0 3px rgba(91, 155, 213, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.login-form >>> .el-input__inner:hover {
|
|
|
+ border-color: #8FC5E8;
|
|
|
+}
|
|
|
+
|
|
|
+.login-form >>> .el-input__prefix {
|
|
|
+ left: 0;
|
|
|
+ width: 42px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.input-icon {
|
|
|
+ font-size: 18px;
|
|
|
+ color: #94A3B8;
|
|
|
+ transition: color 0.25s;
|
|
|
+}
|
|
|
+
|
|
|
+.login-form >>> .el-input.is-focused .input-icon {
|
|
|
+ color: #5B9BD5;
|
|
|
+}
|
|
|
+
|
|
|
+.login-form >>> .el-form-item {
|
|
|
+ margin-bottom: 22px;
|
|
|
+}
|
|
|
+
|
|
|
+.captcha-item {
|
|
|
+ margin-bottom: 18px !important;
|
|
|
}
|
|
|
|
|
|
.login-btn {
|
|
|
width: 100%;
|
|
|
+ height: 44px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ letter-spacing: 6px;
|
|
|
+ border-radius: 10px;
|
|
|
+ background: linear-gradient(135deg, #5B9BD5, #3A7CC4);
|
|
|
+ border: none;
|
|
|
+ transition: all 0.3s;
|
|
|
+}
|
|
|
+
|
|
|
+.login-btn:hover {
|
|
|
+ background: linear-gradient(135deg, #6BA8DE, #4A86CE);
|
|
|
+ box-shadow: 0 4px 16px rgba(91, 155, 213, 0.35);
|
|
|
+ transform: translateY(-1px);
|
|
|
+}
|
|
|
+
|
|
|
+.login-btn:active {
|
|
|
+ transform: translateY(0);
|
|
|
+}
|
|
|
+
|
|
|
+.login-btn.is-disabled {
|
|
|
+ background: #C0C4CC !important;
|
|
|
+ box-shadow: none !important;
|
|
|
+}
|
|
|
+
|
|
|
+.form-footer {
|
|
|
+ text-align: center;
|
|
|
+ margin-top: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.copyright {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #C0C4CC;
|
|
|
+}
|
|
|
+
|
|
|
+/* ==================== 响应式 ==================== */
|
|
|
+@media screen and (max-width: 900px) {
|
|
|
+ .brand-panel { display: none; }
|
|
|
+ .form-panel {
|
|
|
+ flex: 1;
|
|
|
+ padding: 20px;
|
|
|
+ background: linear-gradient(160deg, #3A7CC4, #6BA8DE);
|
|
|
+ }
|
|
|
+ .form-card {
|
|
|
+ box-shadow: 0 8px 40px rgba(0, 0, 0, 0.12);
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|