leisure-core 1.0.2 → 1.0.3

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.
Files changed (94) hide show
  1. package/index.js +223 -0
  2. package/le-area/index.js +7 -0
  3. package/le-area/src/main.vue +112 -0
  4. package/le-button/index.js +7 -0
  5. package/le-button/src/main.vue +47 -0
  6. package/le-button-attach/index.js +6 -0
  7. package/le-button-attach/src/main.vue +171 -0
  8. package/le-button-msg/index.js +7 -0
  9. package/le-button-msg/src/main.vue +65 -0
  10. package/le-button-qr/index.js +7 -0
  11. package/le-button-qr/src/main.vue +96 -0
  12. package/le-date-picker/index.js +7 -0
  13. package/le-date-picker/src/main.vue +67 -0
  14. package/le-date-picker-auto/index.js +6 -0
  15. package/le-date-picker-auto/src/main.vue +131 -0
  16. package/le-dialog-container/index.js +7 -0
  17. package/le-dialog-container/src/main.vue +80 -0
  18. package/le-form/index.js +7 -0
  19. package/le-form/src/main.vue +13 -0
  20. package/le-form-item/index.js +7 -0
  21. package/le-form-item/src/main.vue +13 -0
  22. package/le-home/index.js +7 -0
  23. package/le-home/src/LeHeaderMenu.vue +60 -0
  24. package/le-home/src/main.vue +1307 -0
  25. package/le-home/src/sub.vue +82 -0
  26. package/le-image/index.js +7 -0
  27. package/le-image/src/main.vue +53 -0
  28. package/le-input/index.js +7 -0
  29. package/le-input/src/main.vue +15 -0
  30. package/le-input-advanced/index.js +7 -0
  31. package/le-input-advanced/src/main.vue +71 -0
  32. package/le-input-number/index.js +7 -0
  33. package/le-input-number/src/main.vue +15 -0
  34. package/le-input-validate/index.js +6 -0
  35. package/le-input-validate/src/main.vue +469 -0
  36. package/le-libs/js/drag.js +78 -0
  37. package/le-libs/js/event.js +3 -0
  38. package/le-libs/js/hrequest.js +76 -0
  39. package/le-libs/js/hrequestFile.js +62 -0
  40. package/le-libs/js/info.js +7 -0
  41. package/le-libs/js/tokens.js +13 -0
  42. package/le-libs/mixins/main.js +48 -0
  43. package/le-list/index.js +7 -0
  44. package/le-list/src/main.vue +645 -0
  45. package/le-list-form/index.js +7 -0
  46. package/le-list-form/src/main.vue +474 -0
  47. package/le-login/index.js +7 -0
  48. package/le-login/src/ForgotPassword.vue +613 -0
  49. package/le-login/src/main.vue +982 -0
  50. package/le-media/index.js +7 -0
  51. package/le-media/src/main.vue +298 -0
  52. package/le-media-list/index.js +7 -0
  53. package/le-media-list/src/main.vue +178 -0
  54. package/le-media-upload/index.js +7 -0
  55. package/le-media-upload/src/main.vue +329 -0
  56. package/le-menu/index.js +7 -0
  57. package/le-menu/src/main.vue +248 -0
  58. package/le-report/index.js +6 -0
  59. package/le-report/src/main.vue +1747 -0
  60. package/le-report/src/rmixins.js +30 -0
  61. package/le-role/index.js +7 -0
  62. package/le-role/src/main.vue +183 -0
  63. package/le-role/src/sub.vue +79 -0
  64. package/le-role-user/index.js +7 -0
  65. package/le-role-user/src/main.vue +160 -0
  66. package/le-role-user/src/sub.vue +90 -0
  67. package/le-select/index.js +7 -0
  68. package/le-select/src/main.vue +49 -0
  69. package/le-select-multi/index.js +6 -0
  70. package/le-select-multi/src/main.vue +816 -0
  71. package/le-select-option/index.js +7 -0
  72. package/le-select-option/src/main.vue +69 -0
  73. package/le-select-search/index.js +7 -0
  74. package/le-select-search/src/main.vue +46 -0
  75. package/le-span/index.js +7 -0
  76. package/le-span/src/main.vue +29 -0
  77. package/le-table-edit/index.js +6 -0
  78. package/le-table-edit/src/main.vue +689 -0
  79. package/le-theme/common/vars.css +131 -0
  80. package/le-theme/iconfont/iconfont.css +125 -0
  81. package/le-theme/iconfont/iconfont.ttf +0 -0
  82. package/le-theme/iconfont/iconfont.woff +0 -0
  83. package/le-theme/iconfont/iconfont.woff2 +0 -0
  84. package/le-theme/index.js +189 -0
  85. package/le-theme/pages/index.css +15 -0
  86. package/le-upload/index.js +7 -0
  87. package/le-upload/src/main.vue +134 -0
  88. package/le-upload-table/index.js +6 -0
  89. package/le-upload-table/src/main.vue +648 -0
  90. package/le-url/index.js +7 -0
  91. package/le-url/src/main.vue +27 -0
  92. package/le-video/index.js +7 -0
  93. package/le-video/src/main.vue +42 -0
  94. package/package.json +1 -6
@@ -0,0 +1,982 @@
1
+ <template>
2
+ <div class="login-wrapper">
3
+ <div class="login-card">
4
+ <!-- 左右布局容器 -->
5
+ <div class="login-layout">
6
+ <!-- 左侧Logo区域 -->
7
+ <div class="left-section">
8
+ <div class="logo-content">
9
+ <div class="logo-circle">
10
+ <i class="el-icon-s-data"></i>
11
+ </div>
12
+ <div class="system-info">
13
+ <h2>{{ title }}</h2>
14
+ <p class="subtitle">{{ title1 }}</p>
15
+ </div>
16
+
17
+ <!-- 浏览器提示移到Logo区域 -->
18
+ <div class="system-tips">
19
+ <p class="tip">
20
+ <i class="el-icon-warning-outline"></i>
21
+ 建议使用Chrome、Edge等现代浏览器
22
+ </p>
23
+ </div>
24
+
25
+ <!-- 左侧装饰元素 -->
26
+ <div class="decorative-line"></div>
27
+ </div>
28
+ </div>
29
+
30
+ <!-- 右侧表单区域 -->
31
+ <div class="right-section">
32
+ <!-- 表单容器 -->
33
+ <div class="form-container">
34
+ <div class="form-header">
35
+ <h3>用户登录</h3>
36
+ <p>请输入您的账号信息</p>
37
+ </div>
38
+
39
+ <el-form
40
+ ref="loginForm"
41
+ :model="formdata"
42
+ :rules="rules"
43
+ class="login-form"
44
+ @submit.native.prevent="handleLodin"
45
+ >
46
+ <!-- 用户名 -->
47
+ <el-form-item label="用户名" prop="account" class="form-item">
48
+ <el-input
49
+ v-model="formdata.account"
50
+ placeholder="请输入用户名"
51
+ prefix-icon="el-icon-user"
52
+ class="custom-input"
53
+ @keydown.enter.native="nextFocus(0)"
54
+ />
55
+ </el-form-item>
56
+
57
+ <!-- 密码 -->
58
+ <el-form-item label="密码" prop="pwd" class="form-item">
59
+ <el-input
60
+ v-model="formdata.pwd"
61
+ type="password"
62
+ placeholder="请输入密码"
63
+ show-password
64
+ prefix-icon="el-icon-lock"
65
+ class="custom-input"
66
+ @keydown.enter.native="nextFocus(1)"
67
+ />
68
+ </el-form-item>
69
+
70
+ <!-- 验证码区域(移除label) -->
71
+ <el-form-item
72
+ prop="captcha"
73
+ class="captcha-item"
74
+ v-if="captchaRequired"
75
+ >
76
+ <div class="captcha-wrapper">
77
+ <el-input
78
+ v-model="formdata.captcha"
79
+ placeholder="请输入6位验证码"
80
+ class="captcha-input"
81
+ prefix-icon="el-icon-message"
82
+ maxlength="6"
83
+ @keydown.enter.native="handleLodin"
84
+ ></el-input>
85
+ <el-button
86
+ class="captcha-button"
87
+ type="primary"
88
+ :disabled="isDis || isCounting"
89
+ @click="sendCaptcha"
90
+ :loading="sending"
91
+ >
92
+ <span class="button-text">
93
+ {{ isCounting ? `${retime}秒` : "获取验证码" }}
94
+ </span>
95
+ </el-button>
96
+ </div>
97
+ </el-form-item>
98
+
99
+ <!-- 登录按钮 -->
100
+ <el-form-item class="login-btn-item">
101
+ <el-button
102
+ type="primary"
103
+ class="login-btn"
104
+ :loading="loading"
105
+ @click="handleLodin"
106
+ >
107
+ <span v-if="!loading">登录系统</span>
108
+ <span v-else>登录中...</span>
109
+ </el-button>
110
+ </el-form-item>
111
+
112
+ <!-- 忘记密码链接 -->
113
+ <div class="forgot-link" v-if="showForgotPassword">
114
+ <a href="javascript:;" @click="openForgotDialog">忘记密码?</a>
115
+ </div>
116
+ </el-form>
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </div>
121
+
122
+ <!-- 忘记密码弹窗(独立组件) -->
123
+ <ForgotPassword
124
+ v-if="showForgotPassword"
125
+ v-model="forgotVisible"
126
+ :email-enabled="emailForgotEnabled"
127
+ @sendCaptcha="$emit('sendForgotCaptcha', $event)"
128
+ @verifyCaptcha="$emit('verifyForgotCaptcha', $event)"
129
+ @resetPassword="$emit('resetPassword', $event)"
130
+ @finish="onForgotFinish"
131
+ />
132
+ </div>
133
+ </template>
134
+
135
+ <script>
136
+ import { setToken } from "../../le-libs/js/tokens";
137
+ import ForgotPassword from "./ForgotPassword.vue";
138
+ export default {
139
+ name: "le-login",
140
+ components: { ForgotPassword },
141
+ props: {
142
+ home: {
143
+ type: String,
144
+ default: "/home",
145
+ },
146
+ title: {
147
+ type: String,
148
+ default: "张裕酒文化博物馆管理系统",
149
+ },
150
+ title1: {
151
+ type: String,
152
+ default: "Wine Culture Museum Management System",
153
+ },
154
+ // 添加验证码相关props
155
+ captchaRequired: {
156
+ type: Boolean,
157
+ default: true,
158
+ },
159
+ // 是否开启忘记密码功能
160
+ showForgotPassword: {
161
+ type: Boolean,
162
+ default: true,
163
+ },
164
+ // 是否开启邮箱找回密码方式
165
+ emailForgotEnabled: {
166
+ type: Boolean,
167
+ default: true,
168
+ },
169
+ },
170
+ data() {
171
+ return {
172
+ formdata: {
173
+ account: "",
174
+ pwd: "",
175
+ captcha: "",
176
+ },
177
+ rules: {
178
+ account: [
179
+ { required: true, message: "请输入用户名", trigger: "blur" },
180
+ {
181
+ min: 2,
182
+ max: 20,
183
+ message: "长度在 2 到 20 个字符",
184
+ trigger: "blur",
185
+ },
186
+ ],
187
+ pwd: [
188
+ { required: true, message: "请输入密码", trigger: "blur" },
189
+ {
190
+ min: 6,
191
+ max: 20,
192
+ message: "长度在 6 到 20 个字符",
193
+ trigger: "blur",
194
+ },
195
+ ],
196
+ captcha: this.captchaRequired
197
+ ? [
198
+ { required: true, message: "请输入验证码", trigger: "blur" },
199
+ { len: 6, message: "验证码长度为6位", trigger: "blur" },
200
+ {
201
+ pattern: /^\d{6}$/,
202
+ message: "验证码必须是6位数字",
203
+ trigger: "blur",
204
+ },
205
+ ]
206
+ : [],
207
+ },
208
+ loading: false,
209
+ // 验证码相关数据
210
+ sending: false, // 发送中状态
211
+ isCounting: false, // 是否正在倒计时
212
+ retime: 60, // 倒计时时间
213
+ isDis: false, // 按钮是否禁用
214
+ countdownTimer: null, // 倒计时定时器
215
+ // 忘记密码弹窗显示状态(由 ForgotPassword 子组件管理其余状态)
216
+ forgotVisible: false,
217
+ };
218
+ },
219
+ mounted() {
220
+ // 自动聚焦用户名输入框
221
+ this.$nextTick(() => {
222
+ const firstInput = this.$el.querySelector(".custom-input input");
223
+ if (firstInput) {
224
+ firstInput.focus();
225
+ }
226
+ });
227
+
228
+ // 组件销毁前清除定时器
229
+ this.$once("hook:beforeDestroy", () => {
230
+ if (this.countdownTimer) {
231
+ clearInterval(this.countdownTimer);
232
+ }
233
+ });
234
+ },
235
+ methods: {
236
+ nextFocus(index) {
237
+ const inputs = this.$el.querySelectorAll(".custom-input input");
238
+ if (inputs.length > index + 1) {
239
+ inputs[index + 1].focus();
240
+ }
241
+ },
242
+
243
+ handleLodin() {
244
+ this.$refs.loginForm.validate((valid) => {
245
+ if (valid) {
246
+ this.loading = true;
247
+ this.$emit(
248
+ "handleLodin",
249
+ {
250
+ account: this.formdata.account,
251
+ pwd: this.formdata.pwd,
252
+ captcha: this.captchaRequired ? this.formdata.captcha : undefined,
253
+ },
254
+ this.loginAfter,
255
+ this.nav2Home,
256
+ (fail) => {
257
+ this.loading = false;
258
+ this.$message.error(fail || "登录失败");
259
+ },
260
+ );
261
+ }
262
+ });
263
+ },
264
+
265
+ loginAfter(res) {
266
+ this.loading = false;
267
+ const code = res?.data?.code || "";
268
+ if (code === "10000") {
269
+ const data = res.data.data;
270
+ if (data && data.cid && data.cid.length > 0) {
271
+ this.$store.commit("setCid", data.cid);
272
+ }
273
+ this.$store.commit("setUserInfo", data);
274
+ this.$emit("loginAfter", data);
275
+ setToken(res.data.data.token);
276
+ this.$message.success("登录成功");
277
+ }
278
+ },
279
+
280
+ nav2Home() {
281
+ this.$router.push({ path: this.home });
282
+ },
283
+
284
+ closeLoading() {
285
+ this.loading = false;
286
+ },
287
+
288
+ getUserInfo() {
289
+ return this.formdata;
290
+ },
291
+
292
+ validatePhone(phone) {
293
+ const phoneRegex = /^1[3-9]\d{9}$/;
294
+ return phoneRegex.test(phone);
295
+ },
296
+
297
+ // 发送验证码
298
+ sendCaptcha() {
299
+ if (
300
+ !this.formdata.account ||
301
+ !this.validatePhone(this.formdata.account)
302
+ ) {
303
+ this.$message.error("请输入正确的手机号码");
304
+ return false;
305
+ }
306
+
307
+ // 验证密码
308
+ if (!this.formdata.pwd) {
309
+ this.$message.error("请输入密码");
310
+ return false;
311
+ }
312
+
313
+ this.sending = true;
314
+
315
+ // 触发发送验证码事件,父组件可以监听这个事件来处理发送逻辑
316
+ this.$emit("sendCaptcha", {
317
+ account: this.formdata.account,
318
+ pwd: this.formdata.pwd,
319
+ success: this.startCountdown,
320
+ fail: () => {
321
+ this.sending = false;
322
+ },
323
+ });
324
+ },
325
+
326
+ // 开始倒计时
327
+ startCountdown() {
328
+ this.sending = false;
329
+ this.isCounting = true;
330
+ this.isDis = true;
331
+ this.retime = 60;
332
+
333
+ this.countdownTimer = setInterval(() => {
334
+ this.retime--;
335
+ if (this.retime <= 0) {
336
+ clearInterval(this.countdownTimer);
337
+ this.isCounting = false;
338
+ this.isDis = false;
339
+ this.retime = 60;
340
+ }
341
+ }, 1000);
342
+ },
343
+
344
+ // ============ 忘记密码功能 ============
345
+
346
+ // 打开忘记密码弹窗
347
+ openForgotDialog() {
348
+ this.forgotVisible = true;
349
+ },
350
+
351
+ // 忘记密码完成回调:回填账号到登录表单
352
+ onForgotFinish({ account }) {
353
+ if (account) {
354
+ this.formdata.account = account;
355
+ }
356
+ },
357
+ },
358
+ };
359
+ </script>
360
+
361
+ <style lang="scss" scoped>
362
+ .login-wrapper {
363
+ width: 100%;
364
+ max-width: 900px;
365
+ margin: 0 auto;
366
+ padding: 0 20px;
367
+
368
+ @media (max-width: 1024px) {
369
+ max-width: 800px;
370
+ }
371
+
372
+ @media (max-width: 768px) {
373
+ max-width: 100%;
374
+ padding: 0 15px;
375
+ }
376
+ }
377
+
378
+ .login-card {
379
+ background: var(--le-color-card-bg);
380
+ border-radius: 20px;
381
+ padding: 40px;
382
+ box-shadow:
383
+ 0 20px 60px var(--le-color-card-shadow),
384
+ 0 8px 30px rgba(0, 0, 0, 0.08);
385
+ border: 1px solid var(--le-color-card-border);
386
+ overflow: hidden;
387
+
388
+ @media (max-width: 768px) {
389
+ padding: 30px 25px;
390
+ border-radius: 16px;
391
+ }
392
+
393
+ @media (max-width: 480px) {
394
+ padding: 25px 20px;
395
+ }
396
+ }
397
+
398
+ .login-layout {
399
+ display: flex;
400
+ min-height: 500px;
401
+ max-height: 500px;
402
+
403
+ @media (max-width: 768px) {
404
+ flex-direction: column;
405
+ min-height: auto;
406
+ }
407
+ }
408
+
409
+ /* 左侧Logo区域 */
410
+ .left-section {
411
+ flex: 1;
412
+ display: flex;
413
+ align-items: center;
414
+ justify-content: center;
415
+ padding: 40px;
416
+ background: linear-gradient(
417
+ 135deg,
418
+ var(--le-color-section-bg-from) 0%,
419
+ var(--le-color-section-bg-to) 100%
420
+ );
421
+ border-radius: 16px 0 0 16px;
422
+
423
+ @media (max-width: 768px) {
424
+ padding: 30px 25px;
425
+ border-radius: 16px 16px 0 0;
426
+ margin-bottom: 20px;
427
+ }
428
+
429
+ @media (max-width: 480px) {
430
+ padding: 25px 20px;
431
+ }
432
+ }
433
+
434
+ .logo-content {
435
+ text-align: center;
436
+ max-width: 320px;
437
+ display: flex;
438
+ flex-direction: column;
439
+ height: 100%;
440
+ justify-content: center;
441
+
442
+ .logo-circle {
443
+ width: 100px;
444
+ height: 100px;
445
+ background: linear-gradient(
446
+ 135deg,
447
+ var(--le-color-primary) 0%,
448
+ var(--le-color-primary-2) 100%
449
+ );
450
+ border-radius: 20px;
451
+ display: flex;
452
+ align-items: center;
453
+ justify-content: center;
454
+ margin: 0 auto 30px;
455
+ box-shadow:
456
+ 0 15px 35px var(--le-color-primary-shadow),
457
+ 0 5px 15px var(--le-color-primary-shadow-soft);
458
+
459
+ i {
460
+ font-size: 48px;
461
+ color: white;
462
+ }
463
+ }
464
+
465
+ .system-info {
466
+ margin-bottom: 30px;
467
+
468
+ h2 {
469
+ font-size: 28px;
470
+ font-weight: 700;
471
+ color: var(--le-color-text-strong);
472
+ margin: 0 0 15px 0;
473
+ line-height: 1.3;
474
+ letter-spacing: 0.5px;
475
+ }
476
+
477
+ .subtitle {
478
+ font-size: 16px;
479
+ color: var(--le-color-text-regular);
480
+ margin: 0;
481
+ font-weight: 400;
482
+ letter-spacing: 0.5px;
483
+ line-height: 1.5;
484
+ }
485
+ }
486
+
487
+ /* 左侧浏览器提示 */
488
+ .system-tips {
489
+ margin-top: auto;
490
+ padding-top: 20px;
491
+ text-align: center;
492
+ width: 100%;
493
+
494
+ .tip {
495
+ display: inline-flex;
496
+ align-items: center;
497
+ justify-content: center;
498
+ font-size: 12px;
499
+ color: var(--le-color-text-regular);
500
+ margin: 0;
501
+ line-height: 1.5;
502
+
503
+ i {
504
+ margin-right: 6px;
505
+ font-size: 13px;
506
+ color: var(--le-color-text-muted);
507
+ }
508
+ }
509
+ }
510
+
511
+ .decorative-line {
512
+ width: 60px;
513
+ height: 4px;
514
+ background: linear-gradient(
515
+ 90deg,
516
+ var(--le-color-primary) 0%,
517
+ var(--le-color-primary-light) 100%
518
+ );
519
+ border-radius: 2px;
520
+ margin: 20px auto 0;
521
+ }
522
+ }
523
+
524
+ /* 右侧表单区域 */
525
+ .right-section {
526
+ flex: 1.2;
527
+ display: flex;
528
+ flex-direction: column;
529
+ padding: 40px 40px 40px 50px;
530
+
531
+ @media (max-width: 1024px) {
532
+ padding: 40px 40px 40px 40px;
533
+ }
534
+
535
+ @media (max-width: 768px) {
536
+ padding: 0;
537
+ }
538
+ }
539
+
540
+ .form-container {
541
+ flex: 1;
542
+ display: flex;
543
+ flex-direction: column;
544
+ justify-content: center;
545
+ }
546
+
547
+ .form-header {
548
+ margin-bottom: 40px;
549
+
550
+ h3 {
551
+ font-size: 24px;
552
+ font-weight: 700;
553
+ color: var(--le-color-text-strong);
554
+ margin: 0 0 8px 0;
555
+ }
556
+
557
+ p {
558
+ font-size: 14px;
559
+ color: var(--le-color-text-regular);
560
+ margin: 0;
561
+ font-weight: 400;
562
+ }
563
+ }
564
+
565
+ .login-form {
566
+ .form-item {
567
+ margin-bottom: 28px;
568
+
569
+ &:last-of-type {
570
+ margin-bottom: 32px;
571
+ }
572
+
573
+ .el-form-item__label {
574
+ display: block;
575
+ font-size: 14px;
576
+ font-weight: 600;
577
+ color: var(--le-color-text-form);
578
+ margin-bottom: 10px;
579
+ padding-bottom: 0;
580
+ }
581
+ }
582
+
583
+ /* 验证码区域 */
584
+ .captcha-item {
585
+ margin-bottom: 32px;
586
+
587
+ .captcha-wrapper {
588
+ display: flex;
589
+ gap: 12px;
590
+ align-items: center;
591
+
592
+ .captcha-input {
593
+ flex: 3; /* 增大输入框宽度比例 */
594
+
595
+ ::v-deep .el-input__inner {
596
+ height: 52px;
597
+ border-radius: 12px;
598
+ border: 2px solid var(--le-color-border);
599
+ font-size: 15px;
600
+ color: var(--le-color-input-text);
601
+ padding-left: 48px !important;
602
+ padding-right: 16px;
603
+ transition: all 0.2s ease;
604
+ box-sizing: border-box;
605
+
606
+ &:hover {
607
+ border-color: var(--le-color-border-hover);
608
+ }
609
+
610
+ &:focus {
611
+ border-color: var(--le-color-primary);
612
+ box-shadow: 0 0 0 3px var(--le-color-primary-shadow-soft);
613
+ outline: none;
614
+ }
615
+
616
+ &::placeholder {
617
+ color: var(--le-color-placeholder);
618
+ }
619
+ }
620
+
621
+ ::v-deep .el-input__prefix {
622
+ left: 16px;
623
+ display: flex;
624
+ align-items: center;
625
+ justify-content: center;
626
+ pointer-events: none;
627
+
628
+ .el-icon {
629
+ color: var(--le-color-text-muted);
630
+ font-size: 20px;
631
+ }
632
+ }
633
+ }
634
+
635
+ .captcha-button {
636
+ flex: 1; /* 减小按钮宽度比例 */
637
+ min-width: 120px; /* 设置最小宽度 */
638
+ height: 52px;
639
+ border-radius: 12px;
640
+ background: linear-gradient(
641
+ 135deg,
642
+ var(--le-color-success) 0%,
643
+ var(--le-color-success-2) 100%
644
+ );
645
+ border: none;
646
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
647
+ position: relative;
648
+ overflow: hidden;
649
+
650
+ &:hover:not(.is-disabled) {
651
+ transform: translateY(-2px);
652
+ box-shadow: 0 12px 30px var(--le-color-success-shadow);
653
+ background: linear-gradient(
654
+ 135deg,
655
+ var(--le-color-success-2) 0%,
656
+ #047857 100%
657
+ );
658
+ }
659
+
660
+ &:active {
661
+ transform: translateY(0);
662
+ }
663
+
664
+ &:focus {
665
+ outline: none;
666
+ }
667
+
668
+ .button-text {
669
+ font-size: 14px;
670
+ font-weight: 600;
671
+ letter-spacing: 0.5px;
672
+ }
673
+
674
+ &::after {
675
+ content: "";
676
+ position: absolute;
677
+ top: 50%;
678
+ left: 50%;
679
+ width: 5px;
680
+ height: 5px;
681
+ background: rgba(255, 255, 255, 0.5);
682
+ opacity: 0;
683
+ border-radius: 100%;
684
+ transform: scale(1, 1) translate(-50%);
685
+ transform-origin: 50% 50%;
686
+ }
687
+
688
+ &:focus:not(:active)::after {
689
+ animation: ripple 1s ease-out;
690
+ }
691
+ }
692
+ }
693
+ }
694
+ }
695
+
696
+ @keyframes ripple {
697
+ 0% {
698
+ transform: scale(0, 0);
699
+ opacity: 0.5;
700
+ }
701
+ 100% {
702
+ transform: scale(20, 20);
703
+ opacity: 0;
704
+ }
705
+ }
706
+
707
+ ::v-deep .custom-input {
708
+ .el-input {
709
+ display: flex;
710
+ align-items: center;
711
+ }
712
+
713
+ .el-input__inner {
714
+ height: 52px;
715
+ border-radius: 12px;
716
+ border: 2px solid var(--le-color-border);
717
+ font-size: 15px;
718
+ color: var(--le-color-input-text);
719
+ padding-left: 48px !important;
720
+ padding-right: 16px;
721
+ transition: all 0.2s ease;
722
+ box-sizing: border-box;
723
+
724
+ &:hover {
725
+ border-color: var(--le-color-border-hover);
726
+ }
727
+
728
+ &:focus {
729
+ border-color: var(--le-color-primary);
730
+ box-shadow: 0 0 0 3px var(--le-color-primary-shadow-soft);
731
+ outline: none;
732
+ }
733
+
734
+ &::placeholder {
735
+ color: var(--le-color-placeholder);
736
+ }
737
+ }
738
+
739
+ .el-input__prefix {
740
+ left: 16px;
741
+ display: flex;
742
+ align-items: center;
743
+ justify-content: center;
744
+ pointer-events: none;
745
+
746
+ .el-icon {
747
+ color: var(--le-color-text-muted);
748
+ font-size: 20px;
749
+ }
750
+ }
751
+
752
+ .el-input__suffix {
753
+ right: 16px;
754
+ display: flex;
755
+ align-items: center;
756
+
757
+ .el-icon {
758
+ color: var(--le-color-text-muted);
759
+ font-size: 20px;
760
+ cursor: pointer;
761
+ transition: color 0.2s ease;
762
+
763
+ &:hover {
764
+ color: var(--le-color-text-regular);
765
+ }
766
+ }
767
+ }
768
+
769
+ &.el-input--suffix .el-input__inner {
770
+ padding-right: 48px !important;
771
+ }
772
+ }
773
+
774
+ .login-btn-item {
775
+ margin-top: 10px;
776
+ }
777
+
778
+ .forgot-link {
779
+ text-align: right;
780
+ margin-top: -10px;
781
+ padding: 0 2px;
782
+
783
+ a {
784
+ font-size: 13px;
785
+ color: var(--le-color-text-regular);
786
+ text-decoration: none;
787
+ transition: color 0.2s ease;
788
+
789
+ &:hover {
790
+ color: var(--le-color-primary);
791
+ }
792
+ }
793
+ }
794
+
795
+ .login-btn {
796
+ width: 100%;
797
+ height: 52px;
798
+ font-size: 16px;
799
+ font-weight: 600;
800
+ border-radius: 12px;
801
+ background: linear-gradient(
802
+ 135deg,
803
+ var(--le-color-primary) 0%,
804
+ var(--le-color-primary-2) 100%
805
+ );
806
+ border: none;
807
+ transition: all 0.2s ease;
808
+
809
+ &:hover {
810
+ transform: translateY(-2px);
811
+ box-shadow: 0 12px 30px var(--le-color-primary-shadow);
812
+ }
813
+
814
+ &:active {
815
+ transform: translateY(0);
816
+ }
817
+
818
+ &:focus {
819
+ outline: none;
820
+ }
821
+ }
822
+
823
+ /* 暗色皮肤适配已由 LeTheme.set("dark") 统一管理,通过 CSS 变量覆盖:
824
+ * .login-card / .left-section / .system-info / .form-header / .form-item
825
+ * / .custom-input / .captcha-input / .captcha-button 等
826
+ * 详见 le-theme/common/vars.css 与 le-theme/index.js
827
+ */
828
+
829
+ /* 动画效果 */
830
+ @keyframes fadeInLeft {
831
+ from {
832
+ opacity: 0;
833
+ transform: translateX(-20px);
834
+ }
835
+ to {
836
+ opacity: 1;
837
+ transform: translateX(0);
838
+ }
839
+ }
840
+
841
+ @keyframes fadeInRight {
842
+ from {
843
+ opacity: 0;
844
+ transform: translateX(20px);
845
+ }
846
+ to {
847
+ opacity: 1;
848
+ transform: translateX(0);
849
+ }
850
+ }
851
+
852
+ .left-section {
853
+ animation: fadeInLeft 0.6s ease-out;
854
+ }
855
+
856
+ .right-section {
857
+ animation: fadeInRight 0.6s ease-out 0.1s both;
858
+ }
859
+
860
+ /* 响应式调整 */
861
+ @media (max-width: 768px) {
862
+ .login-wrapper {
863
+ max-width: 500px;
864
+ }
865
+
866
+ .login-layout {
867
+ min-height: auto;
868
+ }
869
+
870
+ .left-section {
871
+ animation: none;
872
+ padding: 25px 20px;
873
+ }
874
+
875
+ .right-section {
876
+ animation: none;
877
+ }
878
+
879
+ .logo-content .logo-circle {
880
+ width: 80px;
881
+ height: 80px;
882
+ margin-bottom: 25px;
883
+
884
+ i {
885
+ font-size: 40px;
886
+ }
887
+ }
888
+
889
+ .logo-content .system-info {
890
+ margin-bottom: 25px;
891
+
892
+ h2 {
893
+ font-size: 24px;
894
+ }
895
+
896
+ .subtitle {
897
+ font-size: 14px;
898
+ }
899
+ }
900
+
901
+ .logo-content .system-tips {
902
+ margin-top: 20px;
903
+ padding-top: 15px;
904
+
905
+ .tip {
906
+ font-size: 11px;
907
+ }
908
+ }
909
+
910
+ .form-header {
911
+ margin-bottom: 30px;
912
+
913
+ h3 {
914
+ font-size: 22px;
915
+ }
916
+ }
917
+
918
+ ::v-deep .custom-input .el-input__inner,
919
+ ::v-deep .captcha-input .el-input__inner {
920
+ height: 48px;
921
+ }
922
+
923
+ .captcha-button {
924
+ height: 48px;
925
+ min-width: 90px;
926
+
927
+ .button-text {
928
+ font-size: 13px;
929
+ }
930
+ }
931
+
932
+ .login-btn {
933
+ height: 48px;
934
+ }
935
+ }
936
+
937
+ @media (max-width: 480px) {
938
+ .logo-content .logo-circle {
939
+ width: 70px;
940
+ height: 70px;
941
+ margin-bottom: 20px;
942
+
943
+ i {
944
+ font-size: 36px;
945
+ }
946
+ }
947
+
948
+ .logo-content .system-info {
949
+ h2 {
950
+ font-size: 22px;
951
+ }
952
+ }
953
+
954
+ .form-header {
955
+ margin-bottom: 25px;
956
+
957
+ h3 {
958
+ font-size: 20px;
959
+ }
960
+ }
961
+
962
+ .login-form .form-item,
963
+ .login-form .captcha-item {
964
+ margin-bottom: 24px;
965
+ }
966
+
967
+ /* 移动端验证码区域垂直排列 */
968
+ .captcha-item .captcha-wrapper {
969
+ flex-direction: column;
970
+ gap: 12px;
971
+
972
+ .captcha-input {
973
+ width: 100%;
974
+ }
975
+
976
+ .captcha-button {
977
+ width: 100%;
978
+ min-width: 100%;
979
+ }
980
+ }
981
+ }
982
+ </style>