xto-fronted 0.9.13 → 0.9.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-D_wFQxCz.js → index-0D0QxIuy.js} +1158 -1125
- package/dist/{index-D4Ujmkk6.js → index-BmlwXD1Z.js} +1 -1
- package/dist/{index-COb9F_fj.js → index-CkBG2FzY.js} +1 -1
- package/dist/{index-B2Td6pR9.js → index-CvLee0YB.js} +1 -1
- package/dist/{index-Dqr-rT21.js → index-DKL8X5Zu.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/views/login/index.vue +501 -413
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, reactive } from 'vue'
|
|
2
|
+
import { ref, reactive, computed } from 'vue'
|
|
3
3
|
import { useRouter, useRoute } from 'vue-router'
|
|
4
4
|
import { Button, Icon } from '@xto/base'
|
|
5
5
|
import { Form, FormItem, Input, Checkbox } from '@xto/form'
|
|
@@ -7,9 +7,14 @@ import { Message } from '@xto/feedback'
|
|
|
7
7
|
import { login } from '@/api/auth'
|
|
8
8
|
import { setTokenInfo } from '@/utils/auth'
|
|
9
9
|
import { getAppId, getClientId } from '@/utils/config'
|
|
10
|
+
import { useAppStore } from '@/stores/app'
|
|
10
11
|
|
|
11
12
|
const router = useRouter()
|
|
12
13
|
const route = useRoute()
|
|
14
|
+
const appStore = useAppStore()
|
|
15
|
+
|
|
16
|
+
const appName = computed(() => appStore.appName || 'XTO App')
|
|
17
|
+
const year = new Date().getFullYear()
|
|
13
18
|
|
|
14
19
|
const loading = ref(false)
|
|
15
20
|
const rememberMe = ref(false)
|
|
@@ -21,7 +26,7 @@ const formData = reactive({
|
|
|
21
26
|
|
|
22
27
|
const rules: Record<string, any[]> = {
|
|
23
28
|
uid: [
|
|
24
|
-
{ required: true, message: '
|
|
29
|
+
{ required: true, message: '请输入账号', trigger: 'blur' }
|
|
25
30
|
],
|
|
26
31
|
password: [
|
|
27
32
|
{ required: true, message: '请输入密码', trigger: 'blur' },
|
|
@@ -34,7 +39,10 @@ const formRef = ref()
|
|
|
34
39
|
// 登录
|
|
35
40
|
const handleLogin = async () => {
|
|
36
41
|
try {
|
|
37
|
-
|
|
42
|
+
// Form.validate 返回布尔值(失败不抛异常),校验不通过则终止登录
|
|
43
|
+
const valid = await formRef.value?.validate()
|
|
44
|
+
if (valid === false) return
|
|
45
|
+
|
|
38
46
|
loading.value = true
|
|
39
47
|
|
|
40
48
|
// 调用登录 API
|
|
@@ -71,490 +79,570 @@ const handleLogin = async () => {
|
|
|
71
79
|
|
|
72
80
|
<template>
|
|
73
81
|
<div class="login-page">
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<h1>企业级后台管理解决方案</h1>
|
|
91
|
-
<p>开箱即用的中后台前端/设计解决方案</p>
|
|
92
|
-
</div>
|
|
93
|
-
|
|
94
|
-
<!-- 特性列表 -->
|
|
95
|
-
<div class="brand-features">
|
|
96
|
-
<div class="feature-item">
|
|
97
|
-
<div class="feature-icon">
|
|
98
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
99
|
-
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>
|
|
100
|
-
</svg>
|
|
101
|
-
</div>
|
|
102
|
-
<div class="feature-text">
|
|
103
|
-
<h4>高性能</h4>
|
|
104
|
-
<p>极致的渲染性能与响应速度</p>
|
|
82
|
+
<a class="skip-link" href="#login-card">跳转到登录表单</a>
|
|
83
|
+
|
|
84
|
+
<div class="page">
|
|
85
|
+
<!-- 左侧品牌区 -->
|
|
86
|
+
<aside class="brand-side" aria-hidden="true">
|
|
87
|
+
<div class="deco-grid"></div>
|
|
88
|
+
<div class="deco-glow"></div>
|
|
89
|
+
<div class="deco-line l1"></div>
|
|
90
|
+
<div class="deco-line l2"></div>
|
|
91
|
+
|
|
92
|
+
<div class="brand-inner">
|
|
93
|
+
<div class="brand-logo">
|
|
94
|
+
<div class="logo-mark">X</div>
|
|
95
|
+
<div class="logo-name">
|
|
96
|
+
{{ appName }}
|
|
97
|
+
<small>XTO PLATFORM</small>
|
|
105
98
|
</div>
|
|
106
99
|
</div>
|
|
107
|
-
<div class="feature-item">
|
|
108
|
-
<div class="feature-icon">
|
|
109
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
110
|
-
<rect x="3" y="3" width="18" height="18" rx="2"/>
|
|
111
|
-
<path d="M9 9h6M9 12h6M9 15h4"/>
|
|
112
|
-
</svg>
|
|
113
|
-
</div>
|
|
114
|
-
<div class="feature-text">
|
|
115
|
-
<h4>丰富组件</h4>
|
|
116
|
-
<p>60+ 高质量业务组件</p>
|
|
117
|
-
</div>
|
|
118
|
-
</div>
|
|
119
|
-
<div class="feature-item">
|
|
120
|
-
<div class="feature-icon">
|
|
121
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
122
|
-
<circle cx="12" cy="12" r="10"/>
|
|
123
|
-
<path d="M12 6v6l4 2"/>
|
|
124
|
-
</svg>
|
|
125
|
-
</div>
|
|
126
|
-
<div class="feature-text">
|
|
127
|
-
<h4>持续更新</h4>
|
|
128
|
-
<p>活跃的社区与快速迭代</p>
|
|
129
|
-
</div>
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
100
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
<
|
|
137
|
-
|
|
138
|
-
|
|
101
|
+
<h1 class="brand-title">
|
|
102
|
+
统一身份认证<br>数字化赋能<em>高效协同</em>
|
|
103
|
+
</h1>
|
|
104
|
+
<p class="brand-desc">
|
|
105
|
+
一站式访问所有业务系统<br>
|
|
106
|
+
安全、高效、可信的企业级数字化工作入口
|
|
107
|
+
</p>
|
|
108
|
+
|
|
109
|
+
<!-- 漂浮插画:认证盾牌 + 业务卡片 -->
|
|
110
|
+
<svg class="brand-visual" viewBox="0 0 460 290" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
111
|
+
<defs>
|
|
112
|
+
<linearGradient id="gShield" x1="160" y1="60" x2="300" y2="250" gradientUnits="userSpaceOnUse">
|
|
113
|
+
<stop offset="0" stop-color="#4fa3ff"/>
|
|
114
|
+
<stop offset="1" stop-color="#1e5fd6"/>
|
|
115
|
+
</linearGradient>
|
|
116
|
+
<linearGradient id="gOrbit" x1="0" y1="0" x2="460" y2="290" gradientUnits="userSpaceOnUse">
|
|
117
|
+
<stop offset="0" stop-color="#67e8f9" stop-opacity=".5"/>
|
|
118
|
+
<stop offset=".5" stop-color="#818cf8" stop-opacity=".35"/>
|
|
119
|
+
<stop offset="1" stop-color="#34d399" stop-opacity=".4"/>
|
|
120
|
+
</linearGradient>
|
|
121
|
+
<radialGradient id="gHalo" cx=".5" cy=".5" r=".5">
|
|
122
|
+
<stop offset="0" stop-color="#38bdf8" stop-opacity=".3"/>
|
|
123
|
+
<stop offset="1" stop-color="#38bdf8" stop-opacity="0"/>
|
|
124
|
+
</radialGradient>
|
|
125
|
+
<linearGradient id="gViolet" x1="0" y1="0" x2="0" y2="1">
|
|
126
|
+
<stop offset="0" stop-color="#a78bfa"/>
|
|
127
|
+
<stop offset="1" stop-color="#7c5cf0"/>
|
|
128
|
+
</linearGradient>
|
|
129
|
+
</defs>
|
|
130
|
+
|
|
131
|
+
<!-- 光晕与轨道 -->
|
|
132
|
+
<circle cx="230" cy="160" r="130" fill="url(#gHalo)"/>
|
|
133
|
+
<ellipse cx="230" cy="165" rx="190" ry="105" stroke="url(#gOrbit)" stroke-width="1.5" stroke-dasharray="3 8"/>
|
|
134
|
+
<ellipse cx="230" cy="165" rx="145" ry="78" stroke="rgba(255,255,255,.14)" stroke-width="1"/>
|
|
135
|
+
|
|
136
|
+
<!-- 连接点 -->
|
|
137
|
+
<circle cx="52" cy="120" r="4" fill="#67e8f9"/>
|
|
138
|
+
<circle cx="410" cy="98" r="4" fill="#fbbf24"/>
|
|
139
|
+
<circle cx="392" cy="228" r="3.5" fill="#818cf8"/>
|
|
140
|
+
<path d="M52 120 C 110 90, 140 78, 178 92" stroke="#67e8f9" stroke-opacity=".45" stroke-width="1.2" stroke-dasharray="2 6"/>
|
|
141
|
+
<path d="M410 98 C 360 80, 320 76, 286 92" stroke="#fbbf24" stroke-opacity=".45" stroke-width="1.2" stroke-dasharray="2 6"/>
|
|
142
|
+
|
|
143
|
+
<!-- 中央盾牌 -->
|
|
144
|
+
<g class="float-a">
|
|
145
|
+
<path d="M230 58 L296 84 V150 C296 200 268 232 230 246 C192 232 164 200 164 150 V84 Z" fill="url(#gShield)"/>
|
|
146
|
+
<path d="M230 58 L296 84 V150 C296 200 268 232 230 246 Z" fill="#0b3f9e" fill-opacity=".25"/>
|
|
147
|
+
<rect x="206" y="130" width="48" height="40" rx="8" fill="#fff"/>
|
|
148
|
+
<path d="M214 130 v-8 a16 16 0 0 1 32 0 v8" stroke="#fff" stroke-width="7" stroke-linecap="round" fill="none"/>
|
|
149
|
+
<circle cx="230" cy="148" r="5.5" fill="#1e5fd6"/>
|
|
150
|
+
<rect x="227.5" y="150" width="5" height="11" rx="2.5" fill="#1e5fd6"/>
|
|
151
|
+
</g>
|
|
152
|
+
|
|
153
|
+
<!-- 左侧:数据卡片 -->
|
|
154
|
+
<g class="float-b">
|
|
155
|
+
<rect x="66" y="120" width="96" height="74" rx="12" fill="#ffffff"/>
|
|
156
|
+
<rect x="66" y="120" width="96" height="74" rx="12" stroke="#e2e8f0" stroke-width="1"/>
|
|
157
|
+
<rect x="80" y="134" width="42" height="7" rx="3.5" fill="#cbd5e1"/>
|
|
158
|
+
<rect x="80" y="168" width="10" height="16" rx="3" fill="#f59e0b"/>
|
|
159
|
+
<rect x="96" y="158" width="10" height="26" rx="3" fill="#fbbf24"/>
|
|
160
|
+
<rect x="112" y="150" width="10" height="34" rx="3" fill="#10b981"/>
|
|
161
|
+
<path d="M124 146 L138 134" stroke="#10b981" stroke-width="2.5" stroke-linecap="round"/>
|
|
162
|
+
<path d="M133 133 h6 v6" stroke="#10b981" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
163
|
+
</g>
|
|
164
|
+
|
|
165
|
+
<!-- 右上:齿轮 -->
|
|
166
|
+
<g class="float-c">
|
|
167
|
+
<circle cx="330" cy="86" r="30" fill="url(#gViolet)"/>
|
|
168
|
+
<g fill="#fff">
|
|
169
|
+
<rect x="326.5" y="60" width="7" height="10" rx="2"/>
|
|
170
|
+
<rect x="326.5" y="102" width="7" height="10" rx="2"/>
|
|
171
|
+
<rect x="304" y="82.5" width="10" height="7" rx="2"/>
|
|
172
|
+
<rect x="346" y="82.5" width="10" height="7" rx="2"/>
|
|
173
|
+
<rect x="310.5" y="63" width="7" height="10" rx="2" transform="rotate(-45 314 68)"/>
|
|
174
|
+
<rect x="342.5" y="99" width="7" height="10" rx="2" transform="rotate(-45 346 104)"/>
|
|
175
|
+
<rect x="310.5" y="99" width="7" height="10" rx="2" transform="rotate(45 314 104)"/>
|
|
176
|
+
<rect x="342.5" y="63" width="7" height="10" rx="2" transform="rotate(45 346 68)"/>
|
|
177
|
+
</g>
|
|
178
|
+
<circle cx="330" cy="86" r="12" fill="#fff"/>
|
|
179
|
+
<circle cx="330" cy="86" r="6" fill="#7c5cf0"/>
|
|
180
|
+
</g>
|
|
181
|
+
|
|
182
|
+
<!-- 右下:系统列表卡片 -->
|
|
183
|
+
<g class="float-b">
|
|
184
|
+
<rect x="312" y="150" width="104" height="66" rx="12" fill="#ffffff"/>
|
|
185
|
+
<rect x="312" y="150" width="104" height="66" rx="12" stroke="#e2e8f0" stroke-width="1"/>
|
|
186
|
+
<circle cx="330" cy="168" r="6" fill="#22d3ee"/>
|
|
187
|
+
<rect x="342" y="164" width="52" height="7" rx="3.5" fill="#cbd5e1"/>
|
|
188
|
+
<circle cx="330" cy="186" r="6" fill="#fbbf24"/>
|
|
189
|
+
<rect x="342" y="182" width="40" height="7" rx="3.5" fill="#cbd5e1"/>
|
|
190
|
+
<circle cx="330" cy="204" r="6" fill="#a78bfa"/>
|
|
191
|
+
<rect x="342" y="200" width="46" height="7" rx="3.5" fill="#cbd5e1"/>
|
|
192
|
+
</g>
|
|
193
|
+
|
|
194
|
+
<!-- 左下:认证徽章 -->
|
|
195
|
+
<g class="float-c">
|
|
196
|
+
<circle cx="128" cy="232" r="24" fill="#10b981"/>
|
|
197
|
+
<circle cx="128" cy="232" r="24" stroke="#34d399" stroke-width="4" stroke-opacity=".5"/>
|
|
198
|
+
<path d="M118 232 l7 7 14 -15" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
199
|
+
</g>
|
|
200
|
+
|
|
201
|
+
<!-- 散落装饰 -->
|
|
202
|
+
<path d="M84 62 l0 12 M78 68 l12 0" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
|
|
203
|
+
<path d="M372 262 l0 10 M367 267 l10 0" stroke="#67e8f9" stroke-width="2" stroke-linecap="round"/>
|
|
204
|
+
<circle cx="416" cy="180" r="2.5" fill="#f59e0b"/>
|
|
205
|
+
<circle cx="98" cy="180" r="2.5" fill="#a78bfa"/>
|
|
206
|
+
</svg>
|
|
139
207
|
</div>
|
|
140
|
-
</
|
|
141
|
-
|
|
142
|
-
<!--
|
|
143
|
-
<
|
|
144
|
-
<
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
208
|
+
</aside>
|
|
209
|
+
|
|
210
|
+
<!-- 右侧登录区 -->
|
|
211
|
+
<main class="login-side">
|
|
212
|
+
<section class="login-card" id="login-card">
|
|
213
|
+
<header class="card-header">
|
|
214
|
+
<div class="logo-mark" aria-hidden="true">X</div>
|
|
215
|
+
<h2 class="welcome">账号登录</h2>
|
|
216
|
+
<p class="welcome-sub">欢迎登录{{ appName }}</p>
|
|
217
|
+
</header>
|
|
218
|
+
|
|
219
|
+
<Form
|
|
220
|
+
ref="formRef"
|
|
221
|
+
:model="formData"
|
|
222
|
+
:rules="rules"
|
|
223
|
+
class="login-form"
|
|
224
|
+
label-width="0"
|
|
225
|
+
>
|
|
226
|
+
<FormItem prop="uid">
|
|
227
|
+
<div class="input-wrapper">
|
|
228
|
+
<label class="input-label">账号</label>
|
|
229
|
+
<Input
|
|
230
|
+
v-model="formData.uid"
|
|
231
|
+
placeholder="请输入账号"
|
|
232
|
+
size="large"
|
|
233
|
+
>
|
|
234
|
+
<template #prefix>
|
|
235
|
+
<Icon name="user" :size="18" />
|
|
236
|
+
</template>
|
|
237
|
+
</Input>
|
|
238
|
+
</div>
|
|
239
|
+
</FormItem>
|
|
240
|
+
|
|
241
|
+
<FormItem prop="password">
|
|
242
|
+
<div class="input-wrapper">
|
|
243
|
+
<label class="input-label">密码</label>
|
|
244
|
+
<Input
|
|
245
|
+
v-model="formData.password"
|
|
246
|
+
type="password"
|
|
247
|
+
placeholder="请输入登录密码"
|
|
248
|
+
size="large"
|
|
249
|
+
show-password
|
|
250
|
+
@keyup.enter="handleLogin"
|
|
251
|
+
>
|
|
252
|
+
<template #prefix>
|
|
253
|
+
<Icon name="lock" :size="18" />
|
|
254
|
+
</template>
|
|
255
|
+
</Input>
|
|
256
|
+
</div>
|
|
257
|
+
</FormItem>
|
|
258
|
+
|
|
259
|
+
<div class="form-options">
|
|
260
|
+
<Checkbox v-model="rememberMe">记住账号</Checkbox>
|
|
261
|
+
<a href="#" class="link">忘记密码?</a>
|
|
177
262
|
</div>
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
<label class="input-label">密码</label>
|
|
183
|
-
<Input
|
|
184
|
-
v-model="formData.password"
|
|
185
|
-
type="password"
|
|
186
|
-
placeholder="请输入密码"
|
|
263
|
+
|
|
264
|
+
<FormItem>
|
|
265
|
+
<Button
|
|
266
|
+
type="primary"
|
|
187
267
|
size="large"
|
|
188
|
-
|
|
189
|
-
|
|
268
|
+
:loading="loading"
|
|
269
|
+
class="btn-login"
|
|
270
|
+
@click="handleLogin"
|
|
190
271
|
>
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
<FormItem>
|
|
204
|
-
<Button
|
|
205
|
-
type="primary"
|
|
206
|
-
size="large"
|
|
207
|
-
:loading="loading"
|
|
208
|
-
class="login-btn"
|
|
209
|
-
@click="handleLogin"
|
|
210
|
-
>
|
|
211
|
-
<span v-if="!loading">登 录</span>
|
|
212
|
-
<span v-else>登录中...</span>
|
|
213
|
-
</Button>
|
|
214
|
-
</FormItem>
|
|
215
|
-
</Form>
|
|
216
|
-
|
|
217
|
-
<!-- 底部 -->
|
|
218
|
-
<div class="form-footer">
|
|
219
|
-
<p>其他登录方式</p>
|
|
220
|
-
<div class="social-login">
|
|
221
|
-
<button class="social-btn" title="企业微信">
|
|
222
|
-
<svg viewBox="0 0 24 24" fill="currentColor">
|
|
223
|
-
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>
|
|
224
|
-
</svg>
|
|
225
|
-
</button>
|
|
226
|
-
<button class="social-btn" title="钉钉">
|
|
227
|
-
<svg viewBox="0 0 24 24" fill="currentColor">
|
|
228
|
-
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19-.14.75-.42 1-.68 1.03-.58.05-1.02-.38-1.58-.75-.88-.58-1.38-.94-2.23-1.5-.99-.65-.35-1.01.22-1.59.15-.15 2.71-2.48 2.76-2.69a.2.2 0 00-.05-.18c-.06-.05-.14-.03-.21-.02-.09.02-1.49.95-4.22 2.79-.4.27-.76.41-1.08.4-.36-.01-1.04-.2-1.55-.37-.63-.2-1.12-.31-1.08-.66.02-.18.27-.36.74-.55 2.92-1.27 4.86-2.11 5.83-2.51 2.78-1.16 3.35-1.36 3.73-1.36.08 0 .27.02.39.12.1.08.13.19.14.27-.01.06.01.24 0 .38z"/>
|
|
229
|
-
</svg>
|
|
230
|
-
</button>
|
|
231
|
-
<button class="social-btn" title="飞书">
|
|
232
|
-
<svg viewBox="0 0 24 24" fill="currentColor">
|
|
233
|
-
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
|
|
234
|
-
</svg>
|
|
235
|
-
</button>
|
|
236
|
-
</div>
|
|
237
|
-
</div>
|
|
238
|
-
</div>
|
|
239
|
-
|
|
240
|
-
<!-- 版权信息 -->
|
|
241
|
-
<div class="copyright">
|
|
242
|
-
<p>© 2024 XTO Team. All rights reserved.</p>
|
|
243
|
-
</div>
|
|
272
|
+
{{ loading ? '正在登录…' : '登 录' }}
|
|
273
|
+
</Button>
|
|
274
|
+
</FormItem>
|
|
275
|
+
</Form>
|
|
276
|
+
</section>
|
|
277
|
+
|
|
278
|
+
<!-- 版权信息 -->
|
|
279
|
+
<footer class="footer">
|
|
280
|
+
Copyright © {{ year }} {{ appName }} All Rights Reserved<br>
|
|
281
|
+
建议使用 Chrome / Edge 浏览器访问
|
|
282
|
+
</footer>
|
|
283
|
+
</main>
|
|
244
284
|
</div>
|
|
245
285
|
</div>
|
|
246
286
|
</template>
|
|
247
287
|
|
|
248
288
|
<style lang="scss" scoped>
|
|
249
289
|
.login-page {
|
|
290
|
+
// 设计令牌(来源:桌面 login.html 设计稿)
|
|
291
|
+
--login-accent: #0A6CD1;
|
|
292
|
+
--login-accent-hover: #0857A8;
|
|
293
|
+
--login-accent-ring: rgba(10, 108, 209, 0.18);
|
|
294
|
+
--login-border: #E2E8F0;
|
|
295
|
+
--login-muted: #475569;
|
|
296
|
+
--login-foreground: #020617;
|
|
297
|
+
|
|
298
|
+
// 登录页内整体切换为设计稿蓝(按钮 / 链接 / 聚焦环)
|
|
299
|
+
--xto-color-primary: #0A6CD1;
|
|
300
|
+
--xto-color-primary-light-1: #0857A8;
|
|
301
|
+
--xto-color-primary-light-3: #4A94DC;
|
|
302
|
+
--xto-color-primary-light-9: #E8F1FB;
|
|
303
|
+
--xto-focus-ring: 0 0 0 3px var(--login-accent-ring);
|
|
304
|
+
|
|
250
305
|
width: 100%;
|
|
251
306
|
min-height: 100vh;
|
|
307
|
+
font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Arial, sans-serif;
|
|
308
|
+
color: var(--login-foreground);
|
|
309
|
+
background: #F8FAFC;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.skip-link {
|
|
313
|
+
position: absolute;
|
|
314
|
+
top: -48px;
|
|
315
|
+
left: 16px;
|
|
316
|
+
z-index: 100;
|
|
317
|
+
padding: 10px 18px;
|
|
318
|
+
background: #0F172A;
|
|
319
|
+
color: #fff;
|
|
320
|
+
border-radius: 0 0 8px 8px;
|
|
321
|
+
text-decoration: none;
|
|
322
|
+
transition: top 180ms ease;
|
|
323
|
+
|
|
324
|
+
&:focus {
|
|
325
|
+
top: 0;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.page {
|
|
252
330
|
display: flex;
|
|
253
|
-
|
|
331
|
+
min-height: 100vh;
|
|
332
|
+
min-width: 320px;
|
|
254
333
|
}
|
|
255
334
|
|
|
256
|
-
//
|
|
257
|
-
.
|
|
258
|
-
flex: 1;
|
|
259
|
-
position: relative;
|
|
335
|
+
// 共用 Logo 方块
|
|
336
|
+
.logo-mark {
|
|
260
337
|
display: flex;
|
|
261
338
|
align-items: center;
|
|
262
339
|
justify-content: center;
|
|
263
|
-
|
|
340
|
+
width: 48px;
|
|
341
|
+
height: 48px;
|
|
342
|
+
border-radius: 12px;
|
|
343
|
+
background: var(--login-accent);
|
|
344
|
+
color: #fff;
|
|
345
|
+
font-size: 22px;
|
|
346
|
+
font-weight: 700;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/* ===== 左侧品牌区 ===== */
|
|
350
|
+
.brand-side {
|
|
351
|
+
position: relative;
|
|
352
|
+
flex: 1.15;
|
|
353
|
+
display: flex;
|
|
354
|
+
flex-direction: column;
|
|
355
|
+
justify-content: center;
|
|
356
|
+
padding: 0 8%;
|
|
357
|
+
background: linear-gradient(150deg, #0e2f5c 0%, #164a80 55%, #2268ab 100%);
|
|
358
|
+
color: #fff;
|
|
264
359
|
overflow: hidden;
|
|
265
360
|
|
|
266
|
-
@media (max-width:
|
|
361
|
+
@media (max-width: 900px) {
|
|
267
362
|
display: none;
|
|
268
363
|
}
|
|
364
|
+
}
|
|
269
365
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
display: flex;
|
|
280
|
-
align-items: center;
|
|
281
|
-
gap: 12px;
|
|
282
|
-
margin-bottom: 48px;
|
|
366
|
+
.deco-grid {
|
|
367
|
+
position: absolute;
|
|
368
|
+
inset: 0;
|
|
369
|
+
background-image:
|
|
370
|
+
linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px),
|
|
371
|
+
linear-gradient(90deg, rgba(255, 255, 255, 0.035) 1px, transparent 1px);
|
|
372
|
+
background-size: 72px 72px;
|
|
373
|
+
pointer-events: none;
|
|
374
|
+
}
|
|
283
375
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
376
|
+
.deco-glow {
|
|
377
|
+
position: absolute;
|
|
378
|
+
width: 560px;
|
|
379
|
+
height: 560px;
|
|
380
|
+
border-radius: 50%;
|
|
381
|
+
background: radial-gradient(circle, rgba(30, 120, 210, 0.5) 0%, transparent 65%);
|
|
382
|
+
bottom: -200px;
|
|
383
|
+
right: -140px;
|
|
384
|
+
pointer-events: none;
|
|
385
|
+
}
|
|
289
386
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
387
|
+
.deco-line {
|
|
388
|
+
position: absolute;
|
|
389
|
+
width: 1px;
|
|
390
|
+
height: 42%;
|
|
391
|
+
left: 0;
|
|
392
|
+
background: linear-gradient(180deg, transparent, rgba(255, 255, 255, 0.18), transparent);
|
|
393
|
+
pointer-events: none;
|
|
394
|
+
|
|
395
|
+
&.l1 { top: 8%; }
|
|
396
|
+
&.l2 {
|
|
397
|
+
bottom: 4%;
|
|
398
|
+
background: linear-gradient(180deg, transparent, rgba(70, 150, 230, 0.55), transparent);
|
|
295
399
|
}
|
|
400
|
+
}
|
|
296
401
|
|
|
297
|
-
|
|
298
|
-
|
|
402
|
+
.brand-inner {
|
|
403
|
+
position: relative;
|
|
404
|
+
z-index: 1;
|
|
405
|
+
}
|
|
299
406
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
}
|
|
407
|
+
.brand-logo {
|
|
408
|
+
display: flex;
|
|
409
|
+
align-items: center;
|
|
410
|
+
gap: 14px;
|
|
411
|
+
margin-bottom: 80px;
|
|
306
412
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
}
|
|
413
|
+
.logo-name {
|
|
414
|
+
font-size: 20px;
|
|
415
|
+
font-weight: 600;
|
|
416
|
+
letter-spacing: 2px;
|
|
313
417
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
align-items: flex-start;
|
|
322
|
-
gap: 16px;
|
|
323
|
-
padding: 16px;
|
|
324
|
-
background: rgba(255, 255, 255, 0.08);
|
|
325
|
-
border-radius: var(--xto-border-radius-large, 12px);
|
|
326
|
-
transition: background-color 0.2s ease;
|
|
327
|
-
|
|
328
|
-
&:hover {
|
|
329
|
-
background: rgba(255, 255, 255, 0.14);
|
|
330
|
-
}
|
|
418
|
+
small {
|
|
419
|
+
display: block;
|
|
420
|
+
font-size: 11px;
|
|
421
|
+
font-weight: 400;
|
|
422
|
+
letter-spacing: 3.5px;
|
|
423
|
+
opacity: 0.55;
|
|
424
|
+
margin-top: 3px;
|
|
331
425
|
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
332
428
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
background: rgba(255, 255, 255, 0.2);
|
|
340
|
-
border-radius: var(--xto-border-radius-base, 6px);
|
|
341
|
-
flex-shrink: 0;
|
|
342
|
-
|
|
343
|
-
svg {
|
|
344
|
-
width: 20px;
|
|
345
|
-
height: 20px;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
429
|
+
.brand-title {
|
|
430
|
+
font-size: 40px;
|
|
431
|
+
font-weight: 700;
|
|
432
|
+
line-height: 1.45;
|
|
433
|
+
letter-spacing: 2px;
|
|
434
|
+
color: #fff;
|
|
348
435
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
font-weight: 600;
|
|
353
|
-
margin-bottom: 4px;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
p {
|
|
357
|
-
font-size: 13px;
|
|
358
|
-
opacity: 0.8;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
436
|
+
em {
|
|
437
|
+
font-style: normal;
|
|
438
|
+
color: #8ec3f0;
|
|
361
439
|
}
|
|
440
|
+
}
|
|
362
441
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
.decoration-line {
|
|
373
|
-
flex: 1;
|
|
374
|
-
height: 1px;
|
|
375
|
-
background: linear-gradient(90deg, rgba(255, 255, 255, 0.3), transparent);
|
|
376
|
-
}
|
|
442
|
+
.brand-desc {
|
|
443
|
+
margin-top: 24px;
|
|
444
|
+
max-width: 440px;
|
|
445
|
+
font-size: 15px;
|
|
446
|
+
line-height: 2;
|
|
447
|
+
letter-spacing: 0.5px;
|
|
448
|
+
color: rgba(255, 255, 255, 0.62);
|
|
449
|
+
}
|
|
377
450
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
451
|
+
.brand-visual {
|
|
452
|
+
margin-top: 52px;
|
|
453
|
+
margin-left: 64px;
|
|
454
|
+
max-width: 460px;
|
|
455
|
+
filter: drop-shadow(0 18px 32px rgba(2, 6, 23, 0.35));
|
|
381
456
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
border-radius: 50%;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
457
|
+
// 矮屏先缩小插画,过矮再隐藏,保证品牌区不溢出
|
|
458
|
+
@media (max-height: 840px) {
|
|
459
|
+
max-width: 360px;
|
|
460
|
+
margin-top: 36px;
|
|
389
461
|
}
|
|
390
462
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
position: absolute;
|
|
394
|
-
inset: 0;
|
|
395
|
-
z-index: 1;
|
|
396
|
-
overflow: hidden;
|
|
397
|
-
|
|
398
|
-
.bg-grid {
|
|
399
|
-
position: absolute;
|
|
400
|
-
inset: 0;
|
|
401
|
-
background-image:
|
|
402
|
-
radial-gradient(rgba(255, 255, 255, 0.14) 1.2px, transparent 1.2px),
|
|
403
|
-
linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px),
|
|
404
|
-
linear-gradient(90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px);
|
|
405
|
-
background-size: 28px 28px, 56px 56px, 56px 56px;
|
|
406
|
-
}
|
|
463
|
+
@media (max-height: 700px) {
|
|
464
|
+
display: none;
|
|
407
465
|
}
|
|
408
466
|
}
|
|
409
467
|
|
|
410
|
-
|
|
411
|
-
.login-
|
|
412
|
-
|
|
413
|
-
|
|
468
|
+
.float-a { animation: login-float-y 5.5s ease-in-out infinite; }
|
|
469
|
+
.float-b { animation: login-float-y 7s ease-in-out 0.8s infinite; }
|
|
470
|
+
.float-c { animation: login-float-y 6s ease-in-out 1.6s infinite; }
|
|
471
|
+
|
|
472
|
+
@keyframes login-float-y {
|
|
473
|
+
0%, 100% { transform: translateY(0); }
|
|
474
|
+
50% { transform: translateY(-9px); }
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/* ===== 右侧登录区 ===== */
|
|
478
|
+
.login-side {
|
|
479
|
+
position: relative;
|
|
480
|
+
flex: 1;
|
|
414
481
|
display: flex;
|
|
415
|
-
|
|
482
|
+
align-items: center;
|
|
416
483
|
justify-content: center;
|
|
417
|
-
padding:
|
|
418
|
-
|
|
484
|
+
padding: 40px;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.login-card {
|
|
488
|
+
width: 100%;
|
|
489
|
+
max-width: 424px;
|
|
490
|
+
padding: 52px 48px 44px;
|
|
491
|
+
background: #fff;
|
|
492
|
+
border: 1px solid var(--login-border);
|
|
493
|
+
border-radius: 16px;
|
|
494
|
+
box-shadow: 0 16px 48px rgba(2, 6, 23, 0.06), 0 2px 6px rgba(2, 6, 23, 0.04);
|
|
495
|
+
}
|
|
419
496
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
497
|
+
.card-header {
|
|
498
|
+
text-align: center;
|
|
499
|
+
|
|
500
|
+
.logo-mark {
|
|
501
|
+
margin: 0 auto 22px;
|
|
502
|
+
width: 52px;
|
|
503
|
+
height: 52px;
|
|
504
|
+
font-size: 24px;
|
|
423
505
|
}
|
|
424
506
|
|
|
425
|
-
.
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
507
|
+
.welcome {
|
|
508
|
+
font-size: 24px;
|
|
509
|
+
font-weight: 700;
|
|
510
|
+
letter-spacing: 1px;
|
|
511
|
+
color: var(--login-foreground);
|
|
429
512
|
}
|
|
430
513
|
|
|
431
|
-
.
|
|
432
|
-
margin-
|
|
514
|
+
.welcome-sub {
|
|
515
|
+
margin-top: 8px;
|
|
516
|
+
font-size: 14px;
|
|
517
|
+
color: var(--login-muted);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
433
520
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
font-weight: 600;
|
|
437
|
-
color: var(--xto-color-text-primary, #1F2329);
|
|
438
|
-
margin-bottom: 8px;
|
|
439
|
-
}
|
|
521
|
+
.login-form {
|
|
522
|
+
margin-top: 38px;
|
|
440
523
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
color: var(--xto-color-text-secondary, #86909C);
|
|
444
|
-
}
|
|
524
|
+
.input-wrapper {
|
|
525
|
+
margin-bottom: 2px;
|
|
445
526
|
}
|
|
446
527
|
|
|
447
|
-
.
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
528
|
+
.input-label {
|
|
529
|
+
display: block;
|
|
530
|
+
margin-bottom: 8px;
|
|
531
|
+
font-size: 14px;
|
|
532
|
+
font-weight: 500;
|
|
533
|
+
color: var(--login-foreground);
|
|
534
|
+
}
|
|
451
535
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
color: var(--xto-color-text-regular, #4E5566);
|
|
457
|
-
margin-bottom: 8px;
|
|
458
|
-
}
|
|
536
|
+
:deep(.x-form-item) {
|
|
537
|
+
// 校验错误信息以绝对定位挂在表单项底部,预留空间避免与下一项重叠
|
|
538
|
+
margin-bottom: 28px;
|
|
539
|
+
}
|
|
459
540
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
541
|
+
:deep(.x-form-item__error) {
|
|
542
|
+
line-height: 1.5;
|
|
543
|
+
}
|
|
463
544
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
545
|
+
:deep(.x-input.x-input--large) {
|
|
546
|
+
height: 48px;
|
|
547
|
+
border: 1.5px solid var(--login-border);
|
|
548
|
+
border-radius: 10px;
|
|
549
|
+
transition: border-color 180ms ease, box-shadow 180ms ease;
|
|
467
550
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
color: var(--xto-color-text-placeholder, #A9AEB8);
|
|
551
|
+
&:hover {
|
|
552
|
+
border-color: #cbd5e1;
|
|
471
553
|
}
|
|
472
554
|
}
|
|
473
555
|
|
|
474
|
-
.
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
margin-bottom: 24px;
|
|
479
|
-
|
|
480
|
-
.forgot-link {
|
|
481
|
-
font-size: 14px;
|
|
482
|
-
color: var(--xto-color-primary, #4F46E5);
|
|
483
|
-
text-decoration: none;
|
|
484
|
-
transition: color 0.2s;
|
|
485
|
-
|
|
486
|
-
&:hover {
|
|
487
|
-
color: var(--xto-color-primary-dark-1, #4338CA);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
556
|
+
:deep(.x-input__prefix) {
|
|
557
|
+
margin-right: 8px;
|
|
558
|
+
color: #94a3b8;
|
|
559
|
+
transition: color 180ms ease;
|
|
490
560
|
}
|
|
491
561
|
|
|
492
|
-
.
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
font-weight: 500;
|
|
497
|
-
border-radius: var(--xto-border-radius-large, 10px);
|
|
498
|
-
letter-spacing: 4px;
|
|
499
|
-
transition: all 0.3s ease;
|
|
562
|
+
:deep(.x-input:focus-within .x-input__prefix) {
|
|
563
|
+
color: var(--login-accent);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
500
566
|
|
|
501
|
-
|
|
502
|
-
|
|
567
|
+
.form-options {
|
|
568
|
+
display: flex;
|
|
569
|
+
align-items: center;
|
|
570
|
+
justify-content: space-between;
|
|
571
|
+
margin: 2px 0 26px;
|
|
572
|
+
font-size: 14px;
|
|
573
|
+
color: var(--login-muted);
|
|
574
|
+
|
|
575
|
+
.link {
|
|
576
|
+
color: var(--login-accent);
|
|
577
|
+
text-decoration: none;
|
|
578
|
+
transition: color 180ms ease;
|
|
579
|
+
|
|
580
|
+
&:hover {
|
|
581
|
+
color: var(--login-accent-hover);
|
|
582
|
+
text-decoration: underline;
|
|
503
583
|
}
|
|
504
584
|
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
.btn-login {
|
|
588
|
+
width: 100%;
|
|
589
|
+
height: 48px;
|
|
590
|
+
font-size: 16px;
|
|
591
|
+
font-weight: 600;
|
|
592
|
+
letter-spacing: 4px;
|
|
593
|
+
text-indent: 4px;
|
|
594
|
+
border-radius: 10px;
|
|
595
|
+
transition: background-color 180ms ease, box-shadow 180ms ease, transform 100ms ease;
|
|
596
|
+
|
|
597
|
+
&:hover:not(:disabled) {
|
|
598
|
+
box-shadow: 0 6px 18px rgba(10, 108, 209, 0.32);
|
|
599
|
+
}
|
|
505
600
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
text-align: center;
|
|
601
|
+
&:active:not(:disabled) {
|
|
602
|
+
transform: scale(0.99);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
511
605
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
606
|
+
.footer {
|
|
607
|
+
position: absolute;
|
|
608
|
+
bottom: 20px;
|
|
609
|
+
left: 0;
|
|
610
|
+
width: 100%;
|
|
611
|
+
text-align: center;
|
|
612
|
+
font-size: 12px;
|
|
613
|
+
letter-spacing: 0.5px;
|
|
614
|
+
line-height: 1.9;
|
|
615
|
+
color: var(--login-muted);
|
|
616
|
+
}
|
|
517
617
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
618
|
+
/* ===== 响应式 ===== */
|
|
619
|
+
@media (max-width: 900px) {
|
|
620
|
+
.login-side {
|
|
621
|
+
flex-direction: column;
|
|
622
|
+
justify-content: center;
|
|
623
|
+
padding: 48px 20px 40px;
|
|
624
|
+
}
|
|
523
625
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
display: flex;
|
|
528
|
-
align-items: center;
|
|
529
|
-
justify-content: center;
|
|
530
|
-
background: var(--xto-fill-color, #F2F3F5);
|
|
531
|
-
border: none;
|
|
532
|
-
border-radius: 50%;
|
|
533
|
-
cursor: pointer;
|
|
534
|
-
transition: all 0.2s ease;
|
|
535
|
-
color: var(--xto-color-text-secondary, #86909C);
|
|
536
|
-
|
|
537
|
-
svg {
|
|
538
|
-
width: 20px;
|
|
539
|
-
height: 20px;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
&:hover {
|
|
543
|
-
background: var(--xto-color-primary-light-8, #DCDAFC);
|
|
544
|
-
color: var(--xto-color-primary, #4F46E5);
|
|
545
|
-
transform: translateY(-2px);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
626
|
+
.login-card {
|
|
627
|
+
padding: 40px 26px 34px;
|
|
628
|
+
border-radius: 14px;
|
|
548
629
|
}
|
|
549
630
|
|
|
550
|
-
.
|
|
551
|
-
|
|
552
|
-
|
|
631
|
+
.footer {
|
|
632
|
+
position: static;
|
|
633
|
+
margin-top: 28px;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
553
636
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
637
|
+
/* ===== 无障碍:减少动效 ===== */
|
|
638
|
+
@media (prefers-reduced-motion: reduce) {
|
|
639
|
+
.float-a,
|
|
640
|
+
.float-b,
|
|
641
|
+
.float-c,
|
|
642
|
+
.skip-link,
|
|
643
|
+
.btn-login {
|
|
644
|
+
animation: none;
|
|
645
|
+
transition: none;
|
|
558
646
|
}
|
|
559
647
|
}
|
|
560
|
-
</style>
|
|
648
|
+
</style>
|