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,613 @@
1
+ <template>
2
+ <el-dialog
3
+ title="找回密码"
4
+ :visible.sync="dialogVisible"
5
+ width="480px"
6
+ :close-on-click-modal="false"
7
+ custom-class="forgot-dialog"
8
+ append-to-body
9
+ @closed="resetForm"
10
+ >
11
+ <!-- 自定义紧凑步骤条 -->
12
+ <div class="forgot-progress">
13
+ <div
14
+ v-for="(s, i) in steps"
15
+ :key="i"
16
+ class="progress-item"
17
+ :class="{
18
+ active: step >= i,
19
+ done: step > i,
20
+ }"
21
+ >
22
+ <div class="progress-circle">
23
+ <i v-if="step > i" class="el-icon-check"></i>
24
+ <span v-else>{{ i + 1 }}</span>
25
+ </div>
26
+ <span class="progress-label">{{ s }}</span>
27
+ <div class="progress-line" v-if="i < steps.length - 1"></div>
28
+ </div>
29
+ </div>
30
+
31
+ <el-form
32
+ ref="forgotForm"
33
+ :model="form"
34
+ :rules="rules"
35
+ label-width="0"
36
+ class="forgot-form"
37
+ v-if="step < 2"
38
+ >
39
+ <!-- 步骤1:验证身份 -->
40
+ <div v-if="step === 0">
41
+ <!-- 找回方式切换:手机/邮箱 -->
42
+ <div class="forgot-tabs" v-if="emailEnabled">
43
+ <span
44
+ class="forgot-tab"
45
+ :class="{ active: type === 'phone' }"
46
+ @click="switchType('phone')"
47
+ >手机找回</span
48
+ >
49
+ <span
50
+ class="forgot-tab"
51
+ :class="{ active: type === 'email' }"
52
+ @click="switchType('email')"
53
+ >邮箱找回</span
54
+ >
55
+ </div>
56
+
57
+ <el-form-item prop="account">
58
+ <el-input
59
+ v-model="form.account"
60
+ :placeholder="
61
+ type === 'phone' ? '请输入手机号' : '请输入邮箱'
62
+ "
63
+ :prefix-icon="
64
+ type === 'phone' ? 'el-icon-mobile-phone' : 'el-icon-message'
65
+ "
66
+ class="forgot-input"
67
+ />
68
+ </el-form-item>
69
+ <el-form-item prop="captcha">
70
+ <div class="forgot-captcha-wrapper">
71
+ <el-input
72
+ v-model="form.captcha"
73
+ placeholder="请输入6位验证码"
74
+ prefix-icon="el-icon-key"
75
+ maxlength="6"
76
+ class="forgot-captcha-input"
77
+ ></el-input>
78
+ <el-button
79
+ class="forgot-captcha-btn"
80
+ type="primary"
81
+ :disabled="isDis || isCounting"
82
+ :loading="sending"
83
+ @click="sendCaptcha"
84
+ >
85
+ {{ isCounting ? `${retime}秒` : "获取验证码" }}
86
+ </el-button>
87
+ </div>
88
+ </el-form-item>
89
+ </div>
90
+
91
+ <!-- 步骤2:设置新密码 -->
92
+ <div v-if="step === 1">
93
+ <el-form-item prop="newPwd">
94
+ <el-input
95
+ v-model="form.newPwd"
96
+ type="password"
97
+ placeholder="请输入新密码(6-20位)"
98
+ show-password
99
+ prefix-icon="el-icon-lock"
100
+ class="forgot-input"
101
+ />
102
+ </el-form-item>
103
+ <el-form-item prop="confirmPwd">
104
+ <el-input
105
+ v-model="form.confirmPwd"
106
+ type="password"
107
+ placeholder="请确认新密码"
108
+ show-password
109
+ prefix-icon="el-icon-lock"
110
+ class="forgot-input"
111
+ @keydown.enter.native="submit"
112
+ />
113
+ </el-form-item>
114
+ </div>
115
+ </el-form>
116
+
117
+ <!-- 步骤3:完成 -->
118
+ <div v-if="step === 2" class="forgot-success">
119
+ <i class="el-icon-success"></i>
120
+ <p>密码修改成功!</p>
121
+ <span>请使用新密码登录系统</span>
122
+ </div>
123
+
124
+ <span slot="footer" class="dialog-footer">
125
+ <el-button @click="dialogVisible = false">
126
+ {{ step === 2 ? "关闭" : "取消" }}
127
+ </el-button>
128
+ <el-button
129
+ v-if="step === 0"
130
+ type="primary"
131
+ :loading="submitting"
132
+ @click="nextStep"
133
+ >下一步</el-button
134
+ >
135
+ <el-button
136
+ v-if="step === 1"
137
+ type="primary"
138
+ :loading="submitting"
139
+ @click="submit"
140
+ >确认修改</el-button
141
+ >
142
+ <el-button v-if="step === 2" type="primary" @click="finish"
143
+ >去登录</el-button
144
+ >
145
+ </span>
146
+ </el-dialog>
147
+ </template>
148
+
149
+ <script>
150
+ export default {
151
+ name: "ForgotPassword",
152
+ props: {
153
+ // 是否显示弹窗(v-model 绑定)
154
+ value: {
155
+ type: Boolean,
156
+ default: false,
157
+ },
158
+ // 是否开启邮箱找回方式
159
+ emailEnabled: {
160
+ type: Boolean,
161
+ default: true,
162
+ },
163
+ // 默认找回方式
164
+ defaultType: {
165
+ type: String,
166
+ default: "phone",
167
+ validator: (v) => v === "phone" || v === "email",
168
+ },
169
+ },
170
+ data() {
171
+ return {
172
+ step: 0, // 0:验证身份 1:设置新密码 2:完成
173
+ steps: ["验证", "重置", "完成"], // 紧凑步骤标签
174
+ type: this.defaultType, // 找回方式:phone/email
175
+ submitting: false,
176
+ sending: false,
177
+ isCounting: false,
178
+ isDis: false,
179
+ retime: 60,
180
+ countdownTimer: null,
181
+ form: {
182
+ account: "",
183
+ captcha: "",
184
+ newPwd: "",
185
+ confirmPwd: "",
186
+ },
187
+ rules: {
188
+ account: [
189
+ { required: true, message: "请输入账号", trigger: "blur" },
190
+ {
191
+ validator: (rule, value, callback) => {
192
+ if (!value) return callback();
193
+ if (this.type === "phone") {
194
+ if (!/^1[3-9]\d{9}$/.test(value)) {
195
+ callback(new Error("请输入正确的手机号"));
196
+ } else {
197
+ callback();
198
+ }
199
+ } else {
200
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
201
+ callback(new Error("请输入正确的邮箱"));
202
+ } else {
203
+ callback();
204
+ }
205
+ }
206
+ },
207
+ trigger: "blur",
208
+ },
209
+ ],
210
+ captcha: [
211
+ { required: true, message: "请输入验证码", trigger: "blur" },
212
+ { len: 6, message: "验证码长度为6位", trigger: "blur" },
213
+ {
214
+ pattern: /^\d{6}$/,
215
+ message: "验证码必须是6位数字",
216
+ trigger: "blur",
217
+ },
218
+ ],
219
+ newPwd: [
220
+ { required: true, message: "请输入新密码", trigger: "blur" },
221
+ {
222
+ min: 6,
223
+ max: 20,
224
+ message: "长度在 6 到 20 个字符",
225
+ trigger: "blur",
226
+ },
227
+ ],
228
+ confirmPwd: [
229
+ { required: true, message: "请确认新密码", trigger: "blur" },
230
+ {
231
+ validator: (rule, value, callback) => {
232
+ if (value !== this.form.newPwd) {
233
+ callback(new Error("两次输入的密码不一致"));
234
+ } else {
235
+ callback();
236
+ }
237
+ },
238
+ trigger: "blur",
239
+ },
240
+ ],
241
+ },
242
+ };
243
+ },
244
+ computed: {
245
+ dialogVisible: {
246
+ get() {
247
+ return this.value;
248
+ },
249
+ set(val) {
250
+ this.$emit("input", val);
251
+ },
252
+ },
253
+ },
254
+ watch: {
255
+ value(val) {
256
+ if (val) {
257
+ // 打开时重置到第一步
258
+ this.step = 0;
259
+ this.type = this.defaultType;
260
+ }
261
+ },
262
+ },
263
+ beforeDestroy() {
264
+ if (this.countdownTimer) {
265
+ clearInterval(this.countdownTimer);
266
+ }
267
+ },
268
+ methods: {
269
+ // 切换找回方式
270
+ switchType(t) {
271
+ if (this.type === t) return;
272
+ this.type = t;
273
+ this.form.account = "";
274
+ this.form.captcha = "";
275
+ if (this.$refs.forgotForm) {
276
+ this.$refs.forgotForm.clearValidate(["account", "captcha"]);
277
+ }
278
+ },
279
+
280
+ // 重置表单
281
+ resetForm() {
282
+ this.step = 0;
283
+ this.type = this.defaultType;
284
+ this.form = {
285
+ account: "",
286
+ captcha: "",
287
+ newPwd: "",
288
+ confirmPwd: "",
289
+ };
290
+ this.submitting = false;
291
+ this.sending = false;
292
+ if (this.$refs.forgotForm) {
293
+ this.$refs.forgotForm.resetFields();
294
+ }
295
+ this.$emit("closed");
296
+ },
297
+
298
+ // 发送验证码
299
+ sendCaptcha() {
300
+ if (!this.form.account) {
301
+ this.$message.error(
302
+ this.type === "phone" ? "请输入手机号" : "请输入邮箱"
303
+ );
304
+ return false;
305
+ }
306
+
307
+ // 先校验账号格式
308
+ const isPhone = this.type === "phone";
309
+ const valid = isPhone
310
+ ? /^1[3-9]\d{9}$/.test(this.form.account)
311
+ : /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.form.account);
312
+ if (!valid) {
313
+ this.$message.error(isPhone ? "请输入正确的手机号" : "请输入正确的邮箱");
314
+ return false;
315
+ }
316
+
317
+ this.sending = true;
318
+
319
+ // emit 给父组件,由父组件调用发送验证码接口
320
+ this.$emit("sendCaptcha", {
321
+ account: this.form.account,
322
+ type: this.type,
323
+ success: this.startCountdown,
324
+ fail: () => {
325
+ this.sending = false;
326
+ },
327
+ });
328
+ },
329
+
330
+ // 倒计时
331
+ startCountdown() {
332
+ this.sending = false;
333
+ this.isCounting = true;
334
+ this.isDis = true;
335
+ this.retime = 60;
336
+
337
+ this.countdownTimer = setInterval(() => {
338
+ this.retime--;
339
+ if (this.retime <= 0) {
340
+ clearInterval(this.countdownTimer);
341
+ this.isCounting = false;
342
+ this.isDis = false;
343
+ this.retime = 60;
344
+ }
345
+ }, 1000);
346
+ },
347
+
348
+ // 下一步:验证身份
349
+ nextStep() {
350
+ this.$refs.forgotForm.validateField(["account", "captcha"], (errors) => {
351
+ if (!errors) {
352
+ this.submitting = true;
353
+ // emit 给父组件验证验证码,成功后进入下一步
354
+ this.$emit("verifyCaptcha", {
355
+ account: this.form.account,
356
+ captcha: this.form.captcha,
357
+ type: this.type,
358
+ success: () => {
359
+ this.submitting = false;
360
+ this.step = 1;
361
+ this.$nextTick(() => {
362
+ if (this.$refs.forgotForm) {
363
+ this.$refs.forgotForm.clearValidate();
364
+ }
365
+ });
366
+ },
367
+ fail: (msg) => {
368
+ this.submitting = false;
369
+ this.$message.error(msg || "验证失败");
370
+ },
371
+ });
372
+ }
373
+ });
374
+ },
375
+
376
+ // 确认修改密码
377
+ submit() {
378
+ this.$refs.forgotForm.validateField(["newPwd", "confirmPwd"], (errors) => {
379
+ if (!errors) {
380
+ this.submitting = true;
381
+ // emit 给父组件调用重置密码接口
382
+ this.$emit("resetPassword", {
383
+ account: this.form.account,
384
+ captcha: this.form.captcha,
385
+ newPwd: this.form.newPwd,
386
+ type: this.type,
387
+ success: () => {
388
+ this.submitting = false;
389
+ this.step = 2;
390
+ },
391
+ fail: (msg) => {
392
+ this.submitting = false;
393
+ this.$message.error(msg || "修改失败");
394
+ },
395
+ });
396
+ }
397
+ });
398
+ },
399
+
400
+ // 完成去登录
401
+ finish() {
402
+ this.dialogVisible = false;
403
+ // 把账号回填给父组件,方便用户直接登录
404
+ this.$emit("finish", {
405
+ account: this.form.account,
406
+ });
407
+ },
408
+ },
409
+ };
410
+ </script>
411
+
412
+ <style lang="scss">
413
+ .forgot-dialog {
414
+ border-radius: 16px;
415
+ overflow: hidden;
416
+
417
+ .el-dialog__header {
418
+ padding: 20px 24px;
419
+ border-bottom: 1px solid var(--le-color-border-light);
420
+
421
+ .el-dialog__title {
422
+ font-size: 18px;
423
+ font-weight: 600;
424
+ color: var(--le-color-text-strong);
425
+ }
426
+ }
427
+
428
+ .el-dialog__body {
429
+ padding: 24px;
430
+ }
431
+
432
+ .el-dialog__footer {
433
+ padding: 16px 24px 20px;
434
+ border-top: 1px solid var(--le-color-border-light);
435
+ }
436
+
437
+ /* 自定义紧凑步骤条 */
438
+ .forgot-progress {
439
+ display: flex;
440
+ align-items: center;
441
+ margin-bottom: 28px;
442
+ padding: 0 8px;
443
+
444
+ .progress-item {
445
+ display: flex;
446
+ align-items: center;
447
+ flex: 1;
448
+ position: relative;
449
+
450
+ &:last-child {
451
+ flex: 0;
452
+ }
453
+
454
+ .progress-circle {
455
+ width: 28px;
456
+ height: 28px;
457
+ border-radius: 50%;
458
+ display: flex;
459
+ align-items: center;
460
+ justify-content: center;
461
+ font-size: 13px;
462
+ font-weight: 600;
463
+ flex-shrink: 0;
464
+ background: var(--le-color-fill);
465
+ color: var(--le-color-text-muted);
466
+ border: 2px solid var(--le-color-border);
467
+ transition: all 0.25s ease;
468
+ }
469
+
470
+ .progress-label {
471
+ margin-left: 8px;
472
+ font-size: 13px;
473
+ color: var(--le-color-text-muted);
474
+ white-space: nowrap;
475
+ transition: color 0.25s ease;
476
+ }
477
+
478
+ .progress-line {
479
+ flex: 1;
480
+ height: 2px;
481
+ background: var(--le-color-border);
482
+ margin: 0 10px;
483
+ min-width: 20px;
484
+ transition: background 0.25s ease;
485
+ }
486
+
487
+ /* 当前/已完成状态 */
488
+ &.active {
489
+ .progress-circle {
490
+ background: var(--le-color-primary);
491
+ border-color: var(--le-color-primary);
492
+ color: #fff;
493
+ box-shadow: 0 4px 12px var(--le-color-primary-shadow-soft);
494
+ }
495
+ .progress-label {
496
+ color: var(--le-color-text-strong);
497
+ font-weight: 600;
498
+ }
499
+ }
500
+
501
+ &.done {
502
+ .progress-circle {
503
+ background: var(--le-color-success);
504
+ border-color: var(--le-color-success);
505
+ color: #fff;
506
+ }
507
+ .progress-line {
508
+ background: var(--le-color-success);
509
+ }
510
+ .progress-label {
511
+ color: var(--le-color-text-regular);
512
+ }
513
+ }
514
+ }
515
+ }
516
+
517
+ /* 找回方式切换 tabs */
518
+ .forgot-tabs {
519
+ display: flex;
520
+ margin-bottom: 18px;
521
+ background: var(--le-color-fill-light);
522
+ border-radius: 8px;
523
+ padding: 4px;
524
+
525
+ .forgot-tab {
526
+ flex: 1;
527
+ text-align: center;
528
+ padding: 8px 0;
529
+ font-size: 13px;
530
+ color: var(--le-color-text-regular);
531
+ cursor: pointer;
532
+ border-radius: 6px;
533
+ transition: all 0.2s ease;
534
+ user-select: none;
535
+
536
+ &:hover {
537
+ color: var(--le-color-text-strong);
538
+ }
539
+
540
+ &.active {
541
+ background: var(--le-color-card-bg);
542
+ color: var(--le-color-primary);
543
+ font-weight: 600;
544
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
545
+ }
546
+ }
547
+ }
548
+
549
+ .forgot-form {
550
+ .el-form-item {
551
+ margin-bottom: 20px;
552
+ }
553
+
554
+ .forgot-captcha-wrapper {
555
+ display: flex;
556
+ gap: 10px;
557
+ align-items: center;
558
+ }
559
+
560
+ .forgot-captcha-input {
561
+ flex: 1;
562
+ }
563
+
564
+ .forgot-captcha-btn {
565
+ min-width: 110px;
566
+ height: 44px;
567
+ border-radius: 8px;
568
+ flex-shrink: 0;
569
+ }
570
+ }
571
+
572
+ .forgot-input .el-input__inner,
573
+ .forgot-captcha-input .el-input__inner {
574
+ height: 44px;
575
+ border-radius: 8px;
576
+ font-size: 14px;
577
+ }
578
+
579
+ .forgot-success {
580
+ text-align: center;
581
+ padding: 20px 0 10px;
582
+
583
+ i {
584
+ font-size: 64px;
585
+ color: var(--le-color-success);
586
+ margin-bottom: 16px;
587
+ }
588
+
589
+ p {
590
+ font-size: 18px;
591
+ font-weight: 600;
592
+ color: var(--le-color-text-strong);
593
+ margin: 0 0 8px 0;
594
+ }
595
+
596
+ span {
597
+ font-size: 13px;
598
+ color: var(--le-color-text-regular);
599
+ }
600
+ }
601
+
602
+ .dialog-footer {
603
+ display: flex;
604
+ justify-content: flex-end;
605
+ gap: 10px;
606
+
607
+ .el-button {
608
+ min-width: 90px;
609
+ border-radius: 8px;
610
+ }
611
+ }
612
+ }
613
+ </style>