slider-captcha-sdk 1.0.19 → 1.0.20
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.esm.js +95 -101
- package/dist/index.min.js +1 -1
- package/dist/password-validator.d.ts +13 -17
- package/dist/password-validator.esm.js +22 -48
- package/dist/password-validator.min.js +1 -1
- package/dist/slider-captcha.esm.js +73 -53
- package/dist/slider-captcha.min.js +1 -1
- package/package.json +10 -3
|
@@ -11,7 +11,7 @@ class PopupSliderCaptcha {
|
|
|
11
11
|
apiUrl: '/api/captcha',
|
|
12
12
|
verifyUrl: '/api/captcha/verify',
|
|
13
13
|
throttleDelay: 16,
|
|
14
|
-
clickMaskClose: false
|
|
14
|
+
clickMaskClose: false
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
static CSS_CLASSES = {
|
|
@@ -23,7 +23,7 @@ class PopupSliderCaptcha {
|
|
|
23
23
|
btn: 'slider-captcha-btn',
|
|
24
24
|
hint: 'slider-captcha-hint',
|
|
25
25
|
loading: 'slider-captcha-loading',
|
|
26
|
-
error: 'slider-captcha-error'
|
|
26
|
+
error: 'slider-captcha-error'
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
// 优化:提取CSS样式为独立方法,减少主体代码长度
|
|
@@ -37,7 +37,7 @@ class PopupSliderCaptcha {
|
|
|
37
37
|
MAX_RETRY_ATTEMPTS: 3,
|
|
38
38
|
DEFAULT_TIMEOUT: 30000,
|
|
39
39
|
FLOATING_TIME_DURATION: 2500,
|
|
40
|
-
THROTTLE_DELAY: 16
|
|
40
|
+
THROTTLE_DELAY: 16
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
static ERROR_TYPES = {
|
|
@@ -45,7 +45,7 @@ class PopupSliderCaptcha {
|
|
|
45
45
|
TIMEOUT_ERROR: 'TIMEOUT_ERROR',
|
|
46
46
|
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
47
47
|
IMAGE_LOAD_ERROR: 'IMAGE_LOAD_ERROR',
|
|
48
|
-
CAPTCHA_DATA_ERROR: 'CAPTCHA_DATA_ERROR'
|
|
48
|
+
CAPTCHA_DATA_ERROR: 'CAPTCHA_DATA_ERROR'
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
constructor(options = {}) {
|
|
@@ -54,7 +54,7 @@ class PopupSliderCaptcha {
|
|
|
54
54
|
...options,
|
|
55
55
|
timeout: options.timeout || PopupSliderCaptcha.CONSTANTS.DEFAULT_TIMEOUT,
|
|
56
56
|
maxRetries: options.maxRetries || PopupSliderCaptcha.CONSTANTS.MAX_RETRY_ATTEMPTS,
|
|
57
|
-
throttleDelay: options.throttleDelay || PopupSliderCaptcha.CONSTANTS.THROTTLE_DELAY
|
|
57
|
+
throttleDelay: options.throttleDelay || PopupSliderCaptcha.CONSTANTS.THROTTLE_DELAY
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
this.elements = {};
|
|
@@ -86,7 +86,7 @@ class PopupSliderCaptcha {
|
|
|
86
86
|
currentX: 0,
|
|
87
87
|
startX: 0,
|
|
88
88
|
retryCount: 0,
|
|
89
|
-
isLoading: false
|
|
89
|
+
isLoading: false
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -97,7 +97,7 @@ class PopupSliderCaptcha {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
injectStyles() {
|
|
100
|
-
if (document.querySelector('#slider-captcha-styles')) return
|
|
100
|
+
if (document.querySelector('#slider-captcha-styles')) { return }
|
|
101
101
|
|
|
102
102
|
const style = document.createElement('style');
|
|
103
103
|
style.id = 'slider-captcha-styles';
|
|
@@ -126,7 +126,7 @@ class PopupSliderCaptcha {
|
|
|
126
126
|
['btn', 'div', PopupSliderCaptcha.CSS_CLASSES.btn],
|
|
127
127
|
['icon', 'div', '', '→'],
|
|
128
128
|
['hint', 'div', PopupSliderCaptcha.CSS_CLASSES.hint, '向右滑动完成验证'],
|
|
129
|
-
['error', 'div', PopupSliderCaptcha.CSS_CLASSES.error]
|
|
129
|
+
['error', 'div', PopupSliderCaptcha.CSS_CLASSES.error]
|
|
130
130
|
];
|
|
131
131
|
|
|
132
132
|
// 批量创建元素
|
|
@@ -146,8 +146,8 @@ class PopupSliderCaptcha {
|
|
|
146
146
|
|
|
147
147
|
createElement(tag, className = '', textContent = '') {
|
|
148
148
|
const element = document.createElement(tag);
|
|
149
|
-
if (className) element.className = className;
|
|
150
|
-
if (textContent) element.textContent = textContent;
|
|
149
|
+
if (className) { element.className = className; }
|
|
150
|
+
if (textContent) { element.textContent = textContent; }
|
|
151
151
|
return element
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -164,7 +164,7 @@ class PopupSliderCaptcha {
|
|
|
164
164
|
elements.backgroundImg,
|
|
165
165
|
elements.sliderImg,
|
|
166
166
|
elements.loadingText,
|
|
167
|
-
elements.floatingTime
|
|
167
|
+
elements.floatingTime
|
|
168
168
|
);
|
|
169
169
|
|
|
170
170
|
// 组装滑块轨道
|
|
@@ -192,10 +192,10 @@ class PopupSliderCaptcha {
|
|
|
192
192
|
this.addEventListener(elements.closeBtn, 'click', () => this.hide());
|
|
193
193
|
this.addEventListener(elements.refreshBtn, 'click', () => this.refresh());
|
|
194
194
|
this.addEventListener(elements.overlay, 'click', (e) => {
|
|
195
|
-
if (e.target === elements.overlay && this.options.clickMaskClose) this.hide();
|
|
195
|
+
if (e.target === elements.overlay && this.options.clickMaskClose) { this.hide(); }
|
|
196
196
|
});
|
|
197
197
|
this.addEventListener(document, 'keydown', (e) => {
|
|
198
|
-
if (e.key === 'Escape' && this.state.isVisible) this.hide();
|
|
198
|
+
if (e.key === 'Escape' && this.state.isVisible) { this.hide(); }
|
|
199
199
|
});
|
|
200
200
|
this.addEventListener(document, 'visibilitychange', () => this.handleVisibilityChange());
|
|
201
201
|
|
|
@@ -207,7 +207,7 @@ class PopupSliderCaptcha {
|
|
|
207
207
|
const handlers = {
|
|
208
208
|
start: (e) => this.handleStart(e),
|
|
209
209
|
move: this.throttledHandleMove,
|
|
210
|
-
end: () => this.handleEnd()
|
|
210
|
+
end: () => this.handleEnd()
|
|
211
211
|
};
|
|
212
212
|
|
|
213
213
|
// 滑块事件
|
|
@@ -222,7 +222,7 @@ class PopupSliderCaptcha {
|
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
addEventListener(element, event, handler, options = {}) {
|
|
225
|
-
if (!element || typeof handler !== 'function') return
|
|
225
|
+
if (!element || typeof handler !== 'function') { return }
|
|
226
226
|
|
|
227
227
|
element.addEventListener(event, handler, options);
|
|
228
228
|
this.eventListeners.push({ element, event, handler, options });
|
|
@@ -246,7 +246,7 @@ class PopupSliderCaptcha {
|
|
|
246
246
|
this.cachedDimensions = {
|
|
247
247
|
trackWidth,
|
|
248
248
|
btnWidth,
|
|
249
|
-
maxX: trackWidth - btnWidth
|
|
249
|
+
maxX: trackWidth - btnWidth
|
|
250
250
|
};
|
|
251
251
|
}
|
|
252
252
|
return this.cachedDimensions
|
|
@@ -259,7 +259,7 @@ class PopupSliderCaptcha {
|
|
|
259
259
|
}
|
|
260
260
|
|
|
261
261
|
handleStart(e) {
|
|
262
|
-
if (!this.captchaData || this.state.isDragging || this.state.isLoading) return
|
|
262
|
+
if (!this.captchaData || this.state.isDragging || this.state.isLoading) { return }
|
|
263
263
|
|
|
264
264
|
e.preventDefault();
|
|
265
265
|
this.state.isDragging = true;
|
|
@@ -273,7 +273,7 @@ class PopupSliderCaptcha {
|
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
handleMove(e) {
|
|
276
|
-
if (!this.state.isDragging) return
|
|
276
|
+
if (!this.state.isDragging) { return }
|
|
277
277
|
e.preventDefault();
|
|
278
278
|
|
|
279
279
|
const clientX = this.getClientX(e);
|
|
@@ -284,12 +284,14 @@ class PopupSliderCaptcha {
|
|
|
284
284
|
this.times.push({ time: Date.now(), position: this.getPosition() });
|
|
285
285
|
|
|
286
286
|
// 优化:使用RAF批量更新
|
|
287
|
-
|
|
287
|
+
if (this.rafId) {
|
|
288
|
+
cancelAnimationFrame(this.rafId);
|
|
289
|
+
}
|
|
288
290
|
this.rafId = requestAnimationFrame(() => this.updateSliderPosition());
|
|
289
291
|
}
|
|
290
292
|
|
|
291
293
|
handleEnd() {
|
|
292
|
-
if (!this.state.isDragging) return
|
|
294
|
+
if (!this.state.isDragging) { return }
|
|
293
295
|
|
|
294
296
|
this.times.push({ time: Date.now(), position: this.getPosition() });
|
|
295
297
|
this.state.isDragging = false;
|
|
@@ -350,7 +352,7 @@ class PopupSliderCaptcha {
|
|
|
350
352
|
elements.hint.style.opacity = '0';
|
|
351
353
|
elements.fingerAnimation.style.display = 'none';
|
|
352
354
|
Object.assign(elements.track.style, { pointerEvents: 'none', opacity: '0.6' });
|
|
353
|
-
}
|
|
355
|
+
}
|
|
354
356
|
};
|
|
355
357
|
|
|
356
358
|
if (updates[state]) {
|
|
@@ -417,7 +419,7 @@ class PopupSliderCaptcha {
|
|
|
417
419
|
[PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR]: '请求超时,请重试',
|
|
418
420
|
[PopupSliderCaptcha.ERROR_TYPES.VALIDATION_ERROR]: '验证失败,请重试',
|
|
419
421
|
[PopupSliderCaptcha.ERROR_TYPES.IMAGE_LOAD_ERROR]: '图片加载失败,请刷新重试',
|
|
420
|
-
[PopupSliderCaptcha.ERROR_TYPES.CAPTCHA_DATA_ERROR]: '验证码数据错误,请刷新重试'
|
|
422
|
+
[PopupSliderCaptcha.ERROR_TYPES.CAPTCHA_DATA_ERROR]: '验证码数据错误,请刷新重试'
|
|
421
423
|
};
|
|
422
424
|
|
|
423
425
|
const errorMessage = errorMessages[errorType] || message || '未知错误';
|
|
@@ -427,7 +429,7 @@ class PopupSliderCaptcha {
|
|
|
427
429
|
this.options.onError({
|
|
428
430
|
type: errorType,
|
|
429
431
|
message: errorMessage,
|
|
430
|
-
originalError
|
|
432
|
+
originalError
|
|
431
433
|
});
|
|
432
434
|
}
|
|
433
435
|
|
|
@@ -451,13 +453,13 @@ class PopupSliderCaptcha {
|
|
|
451
453
|
method: 'POST',
|
|
452
454
|
headers: {
|
|
453
455
|
'Content-Type': 'application/json',
|
|
454
|
-
...this.options.headers
|
|
456
|
+
...this.options.headers
|
|
455
457
|
},
|
|
456
458
|
body: JSON.stringify({
|
|
457
459
|
timestamp: Date.now(),
|
|
458
|
-
...this.options.requestData
|
|
460
|
+
...this.options.requestData
|
|
459
461
|
}),
|
|
460
|
-
signal: this.abortController.signal
|
|
462
|
+
signal: this.abortController.signal
|
|
461
463
|
});
|
|
462
464
|
|
|
463
465
|
if (!response.ok) {
|
|
@@ -490,7 +492,7 @@ class PopupSliderCaptcha {
|
|
|
490
492
|
|
|
491
493
|
// 优化:添加验证码数据验证方法
|
|
492
494
|
validateCaptchaData(data) {
|
|
493
|
-
if (!data || typeof data !== 'object') return false
|
|
495
|
+
if (!data || typeof data !== 'object') { return false }
|
|
494
496
|
|
|
495
497
|
const requiredFields = [
|
|
496
498
|
'canvasSrc',
|
|
@@ -500,7 +502,7 @@ class PopupSliderCaptcha {
|
|
|
500
502
|
'blockWidth',
|
|
501
503
|
'blockHeight',
|
|
502
504
|
'blockY',
|
|
503
|
-
'nonceStr'
|
|
505
|
+
'nonceStr'
|
|
504
506
|
];
|
|
505
507
|
const dataObj = data.data || data;
|
|
506
508
|
|
|
@@ -514,17 +516,33 @@ class PopupSliderCaptcha {
|
|
|
514
516
|
return new Promise((resolve, reject) => {
|
|
515
517
|
let hasError = false;
|
|
516
518
|
|
|
519
|
+
// const _onLoad = () => {
|
|
520
|
+
// if (hasError) { return }
|
|
521
|
+
// loadedCount++
|
|
522
|
+
// if (loadedCount === 2) {
|
|
523
|
+
// this.hideLoading()
|
|
524
|
+
// resolve()
|
|
525
|
+
// }
|
|
526
|
+
// }
|
|
527
|
+
//
|
|
528
|
+
// const _onError = (error) => {
|
|
529
|
+
// if (hasError) { return }
|
|
530
|
+
// hasError = true
|
|
531
|
+
// this.handleError(PopupSliderCaptcha.ERROR_TYPES.IMAGE_LOAD_ERROR, '图片加载失败', error)
|
|
532
|
+
// reject(new Error('图片加载失败'))
|
|
533
|
+
// }
|
|
534
|
+
|
|
517
535
|
// 优化:并行加载图片,提高性能
|
|
518
536
|
const loadPromises = [
|
|
519
537
|
this.loadImageAsync(this.elements.backgroundImg, this.captchaData.canvasSrc, {
|
|
520
538
|
width: this.captchaData.canvasWidth,
|
|
521
|
-
height: this.captchaData.canvasHeight
|
|
539
|
+
height: this.captchaData.canvasHeight
|
|
522
540
|
}),
|
|
523
541
|
this.loadImageAsync(this.elements.sliderImg, this.captchaData.blockSrc, {
|
|
524
542
|
width: this.captchaData.blockWidth,
|
|
525
543
|
height: this.captchaData.blockHeight,
|
|
526
|
-
top: this.captchaData.blockY
|
|
527
|
-
})
|
|
544
|
+
top: this.captchaData.blockY
|
|
545
|
+
})
|
|
528
546
|
];
|
|
529
547
|
|
|
530
548
|
Promise.all(loadPromises)
|
|
@@ -560,16 +578,16 @@ class PopupSliderCaptcha {
|
|
|
560
578
|
reject(new Error('图片加载超时'));
|
|
561
579
|
}, 10000); // 10秒超时
|
|
562
580
|
|
|
563
|
-
imgElement.onload = ()
|
|
581
|
+
imgElement.onload = function onImageLoad() {
|
|
564
582
|
this.safeClearTimeout(timeoutId);
|
|
565
583
|
this.imageCache.set(src, imgElement.cloneNode());
|
|
566
584
|
resolve();
|
|
567
|
-
};
|
|
585
|
+
}.bind(this);
|
|
568
586
|
|
|
569
|
-
imgElement.onerror = (error)
|
|
587
|
+
imgElement.onerror = function onImageError(error) {
|
|
570
588
|
this.safeClearTimeout(timeoutId);
|
|
571
589
|
reject(error);
|
|
572
|
-
};
|
|
590
|
+
}.bind(this);
|
|
573
591
|
|
|
574
592
|
imgElement.src = src;
|
|
575
593
|
this.applyStyles(imgElement, styles);
|
|
@@ -579,7 +597,7 @@ class PopupSliderCaptcha {
|
|
|
579
597
|
// 优化:提取样式应用逻辑
|
|
580
598
|
applyStyles(element, styles) {
|
|
581
599
|
Object.entries(styles).forEach(([key, value]) => {
|
|
582
|
-
element.style[key] = typeof value === 'number' ? value
|
|
600
|
+
element.style[key] = typeof value === 'number' ? `${value}px` : value;
|
|
583
601
|
});
|
|
584
602
|
}
|
|
585
603
|
|
|
@@ -589,7 +607,7 @@ class PopupSliderCaptcha {
|
|
|
589
607
|
this.batchUpdateStyles({
|
|
590
608
|
container: { display: 'block' },
|
|
591
609
|
loadingText: { display: 'flex' },
|
|
592
|
-
error: { display: 'none' }
|
|
610
|
+
error: { display: 'none' }
|
|
593
611
|
});
|
|
594
612
|
this.updateUIState('loading');
|
|
595
613
|
}
|
|
@@ -604,14 +622,14 @@ class PopupSliderCaptcha {
|
|
|
604
622
|
this.batchUpdateStyles({
|
|
605
623
|
container: { display: 'block' },
|
|
606
624
|
track: { display: 'block' },
|
|
607
|
-
error: { display: 'none' }
|
|
625
|
+
error: { display: 'none' }
|
|
608
626
|
});
|
|
609
627
|
}
|
|
610
628
|
|
|
611
629
|
showError(message) {
|
|
612
630
|
this.hideLoading();
|
|
613
631
|
this.batchUpdateStyles({
|
|
614
|
-
error: { display: 'block', textContent: message }
|
|
632
|
+
error: { display: 'block', textContent: message }
|
|
615
633
|
});
|
|
616
634
|
}
|
|
617
635
|
|
|
@@ -650,17 +668,17 @@ class PopupSliderCaptcha {
|
|
|
650
668
|
method: 'POST',
|
|
651
669
|
headers: {
|
|
652
670
|
'Content-Type': 'application/json',
|
|
653
|
-
...this.options.headers
|
|
671
|
+
...this.options.headers
|
|
654
672
|
},
|
|
655
673
|
body: JSON.stringify({
|
|
656
674
|
loginVo: {
|
|
657
675
|
nonceStr: this.captchaData.nonceStr,
|
|
658
|
-
value: this.getPosition()
|
|
676
|
+
value: this.getPosition()
|
|
659
677
|
},
|
|
660
678
|
dragEventList: [...this.times],
|
|
661
|
-
...this.options.verifyData
|
|
679
|
+
...this.options.verifyData
|
|
662
680
|
}),
|
|
663
|
-
signal: this.abortController.signal
|
|
681
|
+
signal: this.abortController.signal
|
|
664
682
|
});
|
|
665
683
|
|
|
666
684
|
if (!response.ok) {
|
|
@@ -691,7 +709,7 @@ class PopupSliderCaptcha {
|
|
|
691
709
|
|
|
692
710
|
// 优化:添加验证成功判断方法
|
|
693
711
|
isVerifySuccess(data) {
|
|
694
|
-
if (!data || typeof data !== 'object') return false
|
|
712
|
+
if (!data || typeof data !== 'object') { return false }
|
|
695
713
|
|
|
696
714
|
// 支持多种成功标识
|
|
697
715
|
const successIndicators = [
|
|
@@ -699,16 +717,16 @@ class PopupSliderCaptcha {
|
|
|
699
717
|
data.code === 0,
|
|
700
718
|
data.success === true,
|
|
701
719
|
data.status === 'success',
|
|
702
|
-
data.result === true
|
|
720
|
+
data.result === true
|
|
703
721
|
];
|
|
704
722
|
|
|
705
723
|
return successIndicators.some((indicator) => indicator === true)
|
|
706
724
|
}
|
|
707
725
|
|
|
708
726
|
onVerifySuccess(ticket) {
|
|
709
|
-
const duration = this.dragStartTime
|
|
710
|
-
|
|
711
|
-
|
|
727
|
+
const duration = this.dragStartTime ?
|
|
728
|
+
Date.now() - this.dragStartTime :
|
|
729
|
+
Date.now() - this.startTime;
|
|
712
730
|
const durationText = `验证成功!耗时:${(duration / 1000).toFixed(2)}s`;
|
|
713
731
|
|
|
714
732
|
this.updateUIState('success');
|
|
@@ -716,9 +734,9 @@ class PopupSliderCaptcha {
|
|
|
716
734
|
|
|
717
735
|
this.safeSetTimeout(() => {
|
|
718
736
|
this.options.onSuccess?.({
|
|
719
|
-
ticket
|
|
737
|
+
ticket,
|
|
720
738
|
timestamp: Date.now(),
|
|
721
|
-
duration
|
|
739
|
+
duration
|
|
722
740
|
});
|
|
723
741
|
this.hide();
|
|
724
742
|
}, 2000);
|
|
@@ -757,7 +775,7 @@ class PopupSliderCaptcha {
|
|
|
757
775
|
isDragging: false,
|
|
758
776
|
currentX: 0,
|
|
759
777
|
startX: 0,
|
|
760
|
-
isLoading: false
|
|
778
|
+
isLoading: false
|
|
761
779
|
});
|
|
762
780
|
|
|
763
781
|
this.times = [];
|
|
@@ -829,13 +847,15 @@ class PopupSliderCaptcha {
|
|
|
829
847
|
// 工具函数:节流
|
|
830
848
|
throttle(func, delay) {
|
|
831
849
|
let lastCall = 0;
|
|
832
|
-
|
|
850
|
+
const throttledFunction = (...args) => {
|
|
833
851
|
const now = Date.now();
|
|
834
852
|
if (now - lastCall >= delay) {
|
|
835
853
|
lastCall = now;
|
|
836
854
|
return func.apply(this, args)
|
|
837
855
|
}
|
|
838
|
-
|
|
856
|
+
return undefined
|
|
857
|
+
};
|
|
858
|
+
return throttledFunction
|
|
839
859
|
}
|
|
840
860
|
|
|
841
861
|
destroy() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).SliderCaptcha=e()}(this,function(){"use strict";class PopupSliderCaptcha{static DEFAULTS={width:320,height:155,sliderSize:38,maxRetries:3,timeout:3e4,apiUrl:"/api/captcha",verifyUrl:"/api/captcha/verify",throttleDelay:16,clickMaskClose:!1};static CSS_CLASSES={overlay:"slider-captcha-overlay",modal:"slider-captcha-modal",header:"slider-captcha-header",container:"slider-captcha-container",track:"slider-captcha-track",btn:"slider-captcha-btn",hint:"slider-captcha-hint",loading:"slider-captcha-loading",error:"slider-captcha-error"};static getStyles(){return":root{--sc-primary:#409eff;--sc-success:#67c23a;--sc-danger:#f56c6c;--sc-border:#e4e7eb;--sc-bg:linear-gradient(90deg, #f7f9fa 0%, #e8f4fd 100%);--sc-text:#333;--sc-text-light:#999;--sc-shadow:0 4px 20px rgba(0,0,0,.3);--sc-radius:8px;--sc-transition:.3s ease}.slider-captcha-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);z-index:9999;display:none;justify-content:center;align-items:center;opacity:0;transition:opacity var(--sc-transition)}.slider-captcha-overlay.show{opacity:1}.slider-captcha-modal{background:#fff;border-radius:var(--sc-radius);padding:20px;box-shadow:var(--sc-shadow);position:relative;max-width:90vw;max-height:90vh;transform:scale(.8) translateY(-20px);opacity:0;transition:all var(--sc-transition)}.slider-captcha-modal.show{transform:scale(1) translateY(0);opacity:1}.slider-captcha-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:15px;padding-bottom:10px;border-bottom:1px solid var(--sc-border)}.slider-captcha-container{display:flex;align-items:center;position:relative;border-radius:4px;overflow:hidden;margin-bottom:15px;background:#837a7a;justify-content:center}.slider-captcha-track{width:100%;height:40px;line-height:40px;background:var(--sc-bg);border:1px solid var(--sc-border);border-radius:20px;position:relative;margin-bottom:15px;overflow:hidden}.slider-captcha-btn{width:38px;height:38px;background:#fff;border:1px solid #ccc;border-radius:50%;position:absolute;top:0;left:0;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 2px 4px rgba(0,0,0,.1);transition:all var(--sc-transition);user-select:none;z-index:1}.slider-captcha-loading{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(255,255,255,.6);display:flex;align-items:center;justify-content:center;flex-direction:column;color:#666;font-size:14px;z-index:10;border-radius:4px}.slider-captcha-error{color:var(--sc-danger);font-size:12px;text-align:center;margin-top:10px;display:none}.slider-captcha-title{margin:0;font-size:16px;color:var(--sc-text)}.slider-captcha-close,.slider-captcha-refresh{background:none;border:none;cursor:pointer;color:var(--sc-text-light);padding:0;width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:all var(--sc-transition);position:relative;font-size:0}.slider-captcha-close::before,.slider-captcha-close::after{content:'';position:absolute;width:16px;height:2px;background-color:var(--sc-text-light);border-radius:1px;transition:all var(--sc-transition)}.slider-captcha-close::before{transform:rotate(45deg)}.slider-captcha-close::after{transform:rotate(-45deg)}.slider-captcha-close:hover{background:#f5f5f5;transform:scale(1.1)}.slider-captcha-close:hover::before,.slider-captcha-close:hover::after{background-color:var(--sc-danger)}.slider-captcha-refresh{margin-left:10px}.slider-captcha-refresh svg{width:20px;height:20px;fill:var(--sc-text-light);transition:all var(--sc-transition)}.slider-captcha-refresh:hover{background:#f5f5f5;transform:scale(1.1)}.slider-captcha-refresh:hover svg{fill:var(--sc-primary);transform:rotate(180deg)}.slider-captcha-floating-time{position:absolute;bottom:-40px;left:50%;transform:translateX(-50%);color:#fff;font-size:12px;white-space:nowrap;opacity:0;pointer-events:none;z-index:10;transition:all var(--sc-transition);background:#fff;padding:2px 15px;border-radius:10px}.slider-captcha-floating-time.show{opacity:1;transform:translateX(-50%) translateY(-45px)}.slider-captcha-floating-time.success{color:var(--sc-success)}.slider-captcha-floating-time.fail{color:var(--sc-danger)}.slider-captcha-bg{width:100%;height:100%;object-fit:cover;display:block}.slider-captcha-piece{position:absolute;top:0;left:0;cursor:pointer;transition:none;z-index:2}.slider-captcha-finger{position:absolute;top:50%;left:10px;transform:translateY(-50%);font-size:20px;animation:fingerSlide 2s ease-in-out infinite;pointer-events:none;z-index:1;opacity:.6}.slider-captcha-hint{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:var(--sc-text-light);font-size:14px;pointer-events:none;z-index:1;transition:all var(--sc-transition)}.slider-captcha-header-buttons{display:flex;align-items:center}@keyframes fingerSlide{0%{left:10px;opacity:.6}50%{opacity:1}100%{left:calc(50% - 10px);opacity:.6}}"}static CONSTANTS={CACHE_DURATION:3e5,MAX_RETRY_ATTEMPTS:3,DEFAULT_TIMEOUT:3e4,FLOATING_TIME_DURATION:2500,THROTTLE_DELAY:16};static ERROR_TYPES={NETWORK_ERROR:"NETWORK_ERROR",TIMEOUT_ERROR:"TIMEOUT_ERROR",VALIDATION_ERROR:"VALIDATION_ERROR",IMAGE_LOAD_ERROR:"IMAGE_LOAD_ERROR",CAPTCHA_DATA_ERROR:"CAPTCHA_DATA_ERROR"};constructor(t={}){this.options={...PopupSliderCaptcha.DEFAULTS,...t,timeout:t.timeout||PopupSliderCaptcha.CONSTANTS.DEFAULT_TIMEOUT,maxRetries:t.maxRetries||PopupSliderCaptcha.CONSTANTS.MAX_RETRY_ATTEMPTS,throttleDelay:t.throttleDelay||PopupSliderCaptcha.CONSTANTS.THROTTLE_DELAY},this.elements={},this.state=this.createInitialState(),this.captchaData=null,this.times=[],this.startTime=null,this.eventListeners=[],this.timers=new Set,this.rafId=null,this.cachedDimensions=null,this.imageCache=new Map,this.abortController=null,this.throttledHandleMove=this.throttle(t=>this.handleMove(t),this.options.throttleDelay);try{this.init()}catch(t){this.handleError(PopupSliderCaptcha.ERROR_TYPES.VALIDATION_ERROR,t.message)}}createInitialState(){return{isVisible:!1,isDragging:!1,currentX:0,startX:0,retryCount:0,isLoading:!1}}init(){this.injectStyles(),this.createElements(),this.bindEvents()}injectStyles(){if(document.querySelector("#slider-captcha-styles"))return;const t=document.createElement("style");t.id="slider-captcha-styles",t.textContent=PopupSliderCaptcha.getStyles(),document.head.appendChild(t)}createElements(){const{elements:t,options:e}=this;[["overlay","div",PopupSliderCaptcha.CSS_CLASSES.overlay],["modal","div",PopupSliderCaptcha.CSS_CLASSES.modal],["header","div",PopupSliderCaptcha.CSS_CLASSES.header],["title","h3","slider-captcha-title","安全验证"],["closeBtn","button","slider-captcha-close"],["refreshBtn","button","slider-captcha-refresh"],["container","div",PopupSliderCaptcha.CSS_CLASSES.container],["backgroundImg","img","slider-captcha-bg"],["sliderImg","img","slider-captcha-piece"],["loadingText","div",PopupSliderCaptcha.CSS_CLASSES.loading,"加载中..."],["floatingTime","div","slider-captcha-floating-time"],["track","div",PopupSliderCaptcha.CSS_CLASSES.track],["fingerAnimation","div","slider-captcha-finger","👉"],["btn","div",PopupSliderCaptcha.CSS_CLASSES.btn],["icon","div","","→"],["hint","div",PopupSliderCaptcha.CSS_CLASSES.hint,"向右滑动完成验证"],["error","div",PopupSliderCaptcha.CSS_CLASSES.error]].forEach(([e,s,i,a])=>{t[e]=this.createElement(s,i,a)}),t.container.style.cssText=`width:${e.width}px;height:${e.height}px`,t.refreshBtn.innerHTML='<svg viewBox="0 0 24 24"><path d="M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z"/></svg>',this.assembleDOM(),this.setInitialState()}createElement(t,e="",s=""){const i=document.createElement(t);return e&&(i.className=e),s&&(i.textContent=s),i}assembleDOM(){const{elements:t}=this,e=this.createElement("div","slider-captcha-header-buttons");e.append(t.refreshBtn,t.closeBtn),t.header.append(t.title,e),t.container.append(t.backgroundImg,t.sliderImg,t.loadingText,t.floatingTime),t.btn.appendChild(t.icon),t.track.append(t.fingerAnimation,t.btn,t.hint),t.modal.append(t.header,t.container,t.track,t.error),t.overlay.appendChild(t.modal),document.body.appendChild(t.overlay)}setInitialState(){Object.assign(this.elements.container.style,{display:"none"}),Object.assign(this.elements.track.style,{display:"none"})}bindEvents(){const{elements:t}=this;this.addEventListener(t.closeBtn,"click",()=>this.hide()),this.addEventListener(t.refreshBtn,"click",()=>this.refresh()),this.addEventListener(t.overlay,"click",e=>{e.target===t.overlay&&this.options.clickMaskClose&&this.hide()}),this.addEventListener(document,"keydown",t=>{"Escape"===t.key&&this.state.isVisible&&this.hide()}),this.addEventListener(document,"visibilitychange",()=>this.handleVisibilityChange()),this.bindSliderEvents()}bindSliderEvents(){const{elements:t}=this,e={start:t=>this.handleStart(t),move:this.throttledHandleMove,end:()=>this.handleEnd()};this.addEventListener(t.btn,"mousedown",e.start),this.addEventListener(t.btn,"touchstart",e.start),this.addEventListener(t.sliderImg,"mousedown",e.start),this.addEventListener(t.sliderImg,"touchstart",e.start),this.addEventListener(document,"mousemove",e.move,{passive:!1}),this.addEventListener(document,"touchmove",e.move,{passive:!1}),this.addEventListener(document,"mouseup",e.end),this.addEventListener(document,"touchend",e.end)}addEventListener(t,e,s,i={}){t&&"function"==typeof s&&(t.addEventListener(e,s,i),this.eventListeners.push({element:t,event:e,handler:s,options:i}))}removeAllEventListeners(){this.eventListeners.forEach(({element:t,event:e,handler:s,options:i})=>{try{t?.removeEventListener?.(e,s,i)}catch(t){}}),this.eventListeners.length=0}getDimensions(){if(!this.cachedDimensions){const t=this.elements.track.offsetWidth,e=this.elements.btn.offsetWidth;this.cachedDimensions={trackWidth:t,btnWidth:e,maxX:t-e}}return this.cachedDimensions}getPosition(){const{maxX:t}=this.getDimensions(),e=this.state.currentX/t;return Math.round(e*(this.options.width-this.options.sliderSize))}handleStart(t){!this.captchaData||this.state.isDragging||this.state.isLoading||(t.preventDefault(),this.state.isDragging=!0,this.state.startX=this.getClientX(t)-this.state.currentX,this.dragStartTime=Date.now(),this.times=[{time:Date.now(),position:this.getPosition()}],this.setTransition(!1),this.updateUIState("dragging"),this.cachedDimensions=null)}handleMove(t){if(!this.state.isDragging)return;t.preventDefault();const e=this.getClientX(t)-this.state.startX,{maxX:s}=this.getDimensions();this.state.currentX=Math.max(0,Math.min(e,s)),this.times.push({time:Date.now(),position:this.getPosition()}),this.rafId&&cancelAnimationFrame(this.rafId),this.rafId=requestAnimationFrame(()=>this.updateSliderPosition())}handleEnd(){this.state.isDragging&&(this.times.push({time:Date.now(),position:this.getPosition()}),this.state.isDragging=!1,this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null),this.verify())}handleVisibilityChange(){const t=document.hidden?"paused":"running";this.elements.fingerAnimation&&(this.elements.fingerAnimation.style.animationPlayState=t)}getClientX(t){return t.type.includes("touch")?t.touches[0].clientX:t.clientX}setTransition(t){const e=t?"all 0.3s ease":"none";requestAnimationFrame(()=>{this.elements.btn.style.transition=e,this.elements.sliderImg.style.transition=e})}updateUIState(t){const{elements:e}=this,s={dragging:()=>{e.hint.style.opacity="0",e.fingerAnimation.style.display="none"},success:()=>{Object.assign(e.btn.style,{background:"var(--sc-success)"}),Object.assign(e.icon.style,{innerHTML:"✓",color:"white"}),e.icon.innerHTML="✓"},fail:()=>{Object.assign(e.btn.style,{background:"var(--sc-danger)"}),Object.assign(e.icon.style,{innerHTML:"✗",color:"white"}),e.icon.innerHTML="✗"},reset:()=>{Object.assign(e.btn.style,{background:"white"}),Object.assign(e.icon.style,{color:"#666"}),e.icon.innerHTML="→",e.fingerAnimation.style.display="block",this.updateHintText("向右滑动完成验证","var(--sc-text-light)")},loading:()=>{e.hint.style.opacity="0",e.fingerAnimation.style.display="none",Object.assign(e.track.style,{pointerEvents:"none",opacity:"0.6"})}};s[t]&&requestAnimationFrame(()=>{s[t](),"loading"!==t&&Object.assign(e.track.style,{pointerEvents:"auto",opacity:"1"})})}updateHintText(t,e){requestAnimationFrame(()=>{Object.assign(this.elements.hint,{textContent:t}),Object.assign(this.elements.hint.style,{color:e,opacity:"1"})})}updateSliderPosition(){const{elements:t,options:e,state:s}=this,{maxX:i}=this.getDimensions(),a=s.currentX/i*(e.width-e.sliderSize),n=s.currentX/i;requestAnimationFrame(()=>{t.btn.style.transform=`translateX(${s.currentX}px)`,t.sliderImg.style.transform=`translateX(${a}px)`,t.fingerAnimation.style.opacity=.8>n?"0.6":"0"})}show(){this.state.isVisible=!0,this.elements.overlay.style.display="flex",requestAnimationFrame(()=>{this.elements.overlay.classList.add("show"),this.elements.modal.classList.add("show")}),this.loadCaptcha()}hide(){this.state.isVisible=!1,this.elements.overlay.classList.remove("show"),this.elements.modal.classList.remove("show"),this.safeSetTimeout(()=>{this.elements.overlay.style.display="none",document.body.removeChild(this.elements.overlay),this.reset(),this.options.onClose?.(),this.elements.overlay=null},300)}handleError(t,e,s=null){const i={[PopupSliderCaptcha.ERROR_TYPES.NETWORK_ERROR]:"网络连接失败,请检查网络设置",[PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR]:"请求超时,请重试",[PopupSliderCaptcha.ERROR_TYPES.VALIDATION_ERROR]:"验证失败,请重试",[PopupSliderCaptcha.ERROR_TYPES.IMAGE_LOAD_ERROR]:"图片加载失败,请刷新重试",[PopupSliderCaptcha.ERROR_TYPES.CAPTCHA_DATA_ERROR]:"验证码数据错误,请刷新重试"}[t]||e||"未知错误";this.options.onError&&this.options.onError({type:t,message:i,originalError:s}),this.showError(i)}async loadCaptcha(){try{this.showLoading(),this.startTime=Date.now(),this.abortController&&this.abortController.abort(),this.abortController=new AbortController;const t=await fetch(this.options.apiUrl,{method:"POST",headers:{"Content-Type":"application/json",...this.options.headers},body:JSON.stringify({timestamp:Date.now(),...this.options.requestData}),signal:this.abortController.signal});if(!t.ok)throw Error(`HTTP ${t.status}: ${t.statusText}`);const e=await t.json();if(!this.validateCaptchaData(e))throw Error("验证码数据格式错误");this.captchaData=e.data,this.showCaptcha(),await this.renderCaptcha()}catch(t){"AbortError"===t.name?this.handleError(PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR,"请求被取消"):t.message.includes("Failed to fetch")||t.message.includes("NetworkError")?this.handleError(PopupSliderCaptcha.ERROR_TYPES.NETWORK_ERROR,"网络连接失败"):this.handleError(PopupSliderCaptcha.ERROR_TYPES.CAPTCHA_DATA_ERROR,t.message,t)}}validateCaptchaData(t){if(!t||"object"!=typeof t)return!1;const e=t.data||t;return["canvasSrc","blockSrc","canvasWidth","canvasHeight","blockWidth","blockHeight","blockY","nonceStr"].every(t=>{const s=e[t];return null!=s&&""!==s})}async renderCaptcha(){return new Promise((t,e)=>{let s=!1;const i=[this.loadImageAsync(this.elements.backgroundImg,this.captchaData.canvasSrc,{width:this.captchaData.canvasWidth,height:this.captchaData.canvasHeight}),this.loadImageAsync(this.elements.sliderImg,this.captchaData.blockSrc,{width:this.captchaData.blockWidth,height:this.captchaData.blockHeight,top:this.captchaData.blockY})];Promise.all(i).then(()=>{s||(this.hideLoading(),t())}).catch(t=>{s||(s=!0,this.handleError(PopupSliderCaptcha.ERROR_TYPES.IMAGE_LOAD_ERROR,"图片加载失败",t),e(t))})})}async loadImageAsync(t,e,s){return new Promise((i,a)=>{if(this.imageCache.has(e)){const a=this.imageCache.get(e);return t.src=a.src,this.applyStyles(t,s),void i()}const n=this.safeSetTimeout(()=>{a(Error("图片加载超时"))},1e4);t.onload=()=>{this.safeClearTimeout(n),this.imageCache.set(e,t.cloneNode()),i()},t.onerror=t=>{this.safeClearTimeout(n),a(t)},t.src=e,this.applyStyles(t,s)})}applyStyles(t,e){Object.entries(e).forEach(([e,s])=>{t.style[e]="number"==typeof s?s+"px":s})}showLoading(){this.state.isLoading=!0,this.batchUpdateStyles({container:{display:"block"},loadingText:{display:"flex"},error:{display:"none"}}),this.updateUIState("loading")}hideLoading(){this.state.isLoading=!1,this.batchUpdateStyles({loadingText:{display:"none"}}),this.updateUIState("reset")}showCaptcha(){this.batchUpdateStyles({container:{display:"block"},track:{display:"block"},error:{display:"none"}})}showError(t){this.hideLoading(),this.batchUpdateStyles({error:{display:"block",textContent:t}})}batchUpdateStyles(t){requestAnimationFrame(()=>{Object.entries(t).forEach(([t,e])=>{const s=this.elements[t];s&&Object.entries(e).forEach(([t,e])=>{"textContent"===t?s.textContent=e:s.style[t]=e})})})}async verify(){if(this.captchaData)try{this.abortController&&this.abortController.abort(),this.abortController=new AbortController;const t=await fetch(this.options.verifyUrl,{method:"POST",headers:{"Content-Type":"application/json",...this.options.headers},body:JSON.stringify({loginVo:{nonceStr:this.captchaData.nonceStr,value:this.getPosition()},dragEventList:[...this.times],...this.options.verifyData}),signal:this.abortController.signal});if(!t.ok)throw Error(`HTTP ${t.status}: ${t.statusText}`);const e=await t.json();this.isVerifySuccess(e)?this.onVerifySuccess(e.data||e.result):this.onVerifyFail(e.message||e.msg||"验证失败,请重试!")}catch(t){"AbortError"===t.name?this.handleError(PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR,"验证请求被取消"):t.message.includes("Failed to fetch")||t.message.includes("NetworkError")?this.handleError(PopupSliderCaptcha.ERROR_TYPES.NETWORK_ERROR,"网络连接失败"):this.handleError(PopupSliderCaptcha.ERROR_TYPES.VALIDATION_ERROR,t.message,t)}else this.onVerifyFail("验证码数据丢失")}isVerifySuccess(t){return!(!t||"object"!=typeof t)&&["0"===t.code,0===t.code,!0===t.success,"success"===t.status,!0===t.result].some(t=>!0===t)}onVerifySuccess(t){const e=this.dragStartTime?Date.now()-this.dragStartTime:Date.now()-this.startTime,s=`验证成功!耗时:${(e/1e3).toFixed(2)}s`;this.updateUIState("success"),this.showFloatingTime(s,"success"),this.safeSetTimeout(()=>{this.options.onSuccess?.({ticket:t,timestamp:Date.now(),duration:e}),this.hide()},2e3)}showFloatingTime(t,e="success"){const{elements:s}=this;s.floatingTime.textContent=t,s.floatingTime.className="slider-captcha-floating-time "+e,this.safeSetTimeout(()=>s.floatingTime.classList.add("show"),100),this.safeSetTimeout(()=>{s.floatingTime.className="slider-captcha-floating-time"},2500)}onVerifyFail(t){this.state.retryCount++,this.updateUIState("fail"),this.showFloatingTime(t,"fail"),this.safeSetTimeout(()=>{this.state.retryCount<this.options.maxRetries?this.reset():this.refresh()},2500)}reset(){this.clearAllTimers(),Object.assign(this.state,{isDragging:!1,currentX:0,startX:0,isLoading:!1}),this.times=[],this.startTime=null,this.dragStartTime=null,this.cachedDimensions=null,requestAnimationFrame(()=>{this.setTransition(!0),this.elements.btn.style.transform="translateX(0px)",this.elements.sliderImg.style.transform="translateX(0px)",this.updateUIState("reset"),this.elements.error.style.display="none"})}refresh(){this.reset(),this.state.retryCount=0,this.loadCaptcha()}safeSetTimeout(t,e){const s=setTimeout(()=>{this.timers.delete(s),t()},e);return this.timers.add(s),s}safeClearTimeout(t){t&&(clearTimeout(t),this.timers.delete(t))}clearAllTimers(){this.timers.forEach(t=>{clearTimeout(t),clearInterval(t)}),this.timers.clear(),this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null)}cleanupImages(){this.elements.backgroundImg&&(this.elements.backgroundImg.src="",this.elements.backgroundImg.onload=null,this.elements.backgroundImg.onerror=null),this.elements.sliderImg&&(this.elements.sliderImg.src="",this.elements.sliderImg.onload=null,this.elements.sliderImg.onerror=null),this.imageCache.clear()}throttle(t,e){let s=0;return function(...i){const a=Date.now();if(a-s>=e)return s=a,t.apply(this,i)}}destroy(){try{this.abortController&&(this.abortController.abort(),this.abortController=null),document.body&&(document.body.style.userSelect="",document.body.style.cursor=""),this.clearAllTimers(),this.removeAllEventListeners(),this.cleanupImages(),this.elements?.overlay?.parentNode&&this.elements.overlay.parentNode.removeChild(this.elements.overlay);const t=document.getElementById("slider-captcha-styles");t&&t.remove(),this.imageCache.clear(),this.cachedDimensions=null,Object.keys(this).forEach(t=>{"constructor"!==t&&(this[t]=null)}),this.options.onDestroy&&this.options.onDestroy()}catch(t){}}static create(t){return new PopupSliderCaptcha(t)}static show(t){const e=new PopupSliderCaptcha(t);return e.show(),e}}return"undefined"!=typeof module&&module.exports?(module.exports=PopupSliderCaptcha,module.exports.default=PopupSliderCaptcha):"function"==typeof define&&define.amd?define([],()=>PopupSliderCaptcha):"undefined"!=typeof window&&(window.PopupSliderCaptcha=PopupSliderCaptcha,window.SliderCaptcha=PopupSliderCaptcha),PopupSliderCaptcha});
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).SliderCaptcha=e()}(this,function(){"use strict";class PopupSliderCaptcha{static DEFAULTS={width:320,height:155,sliderSize:38,maxRetries:3,timeout:3e4,apiUrl:"/api/captcha",verifyUrl:"/api/captcha/verify",throttleDelay:16,clickMaskClose:!1};static CSS_CLASSES={overlay:"slider-captcha-overlay",modal:"slider-captcha-modal",header:"slider-captcha-header",container:"slider-captcha-container",track:"slider-captcha-track",btn:"slider-captcha-btn",hint:"slider-captcha-hint",loading:"slider-captcha-loading",error:"slider-captcha-error"};static getStyles(){return":root{--sc-primary:#409eff;--sc-success:#67c23a;--sc-danger:#f56c6c;--sc-border:#e4e7eb;--sc-bg:linear-gradient(90deg, #f7f9fa 0%, #e8f4fd 100%);--sc-text:#333;--sc-text-light:#999;--sc-shadow:0 4px 20px rgba(0,0,0,.3);--sc-radius:8px;--sc-transition:.3s ease}.slider-captcha-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);z-index:9999;display:none;justify-content:center;align-items:center;opacity:0;transition:opacity var(--sc-transition)}.slider-captcha-overlay.show{opacity:1}.slider-captcha-modal{background:#fff;border-radius:var(--sc-radius);padding:20px;box-shadow:var(--sc-shadow);position:relative;max-width:90vw;max-height:90vh;transform:scale(.8) translateY(-20px);opacity:0;transition:all var(--sc-transition)}.slider-captcha-modal.show{transform:scale(1) translateY(0);opacity:1}.slider-captcha-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:15px;padding-bottom:10px;border-bottom:1px solid var(--sc-border)}.slider-captcha-container{display:flex;align-items:center;position:relative;border-radius:4px;overflow:hidden;margin-bottom:15px;background:#837a7a;justify-content:center}.slider-captcha-track{width:100%;height:40px;line-height:40px;background:var(--sc-bg);border:1px solid var(--sc-border);border-radius:20px;position:relative;margin-bottom:15px;overflow:hidden}.slider-captcha-btn{width:38px;height:38px;background:#fff;border:1px solid #ccc;border-radius:50%;position:absolute;top:0;left:0;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 2px 4px rgba(0,0,0,.1);transition:all var(--sc-transition);user-select:none;z-index:1}.slider-captcha-loading{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(255,255,255,.6);display:flex;align-items:center;justify-content:center;flex-direction:column;color:#666;font-size:14px;z-index:10;border-radius:4px}.slider-captcha-error{color:var(--sc-danger);font-size:12px;text-align:center;margin-top:10px;display:none}.slider-captcha-title{margin:0;font-size:16px;color:var(--sc-text)}.slider-captcha-close,.slider-captcha-refresh{background:none;border:none;cursor:pointer;color:var(--sc-text-light);padding:0;width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:all var(--sc-transition);position:relative;font-size:0}.slider-captcha-close::before,.slider-captcha-close::after{content:'';position:absolute;width:16px;height:2px;background-color:var(--sc-text-light);border-radius:1px;transition:all var(--sc-transition)}.slider-captcha-close::before{transform:rotate(45deg)}.slider-captcha-close::after{transform:rotate(-45deg)}.slider-captcha-close:hover{background:#f5f5f5;transform:scale(1.1)}.slider-captcha-close:hover::before,.slider-captcha-close:hover::after{background-color:var(--sc-danger)}.slider-captcha-refresh{margin-left:10px}.slider-captcha-refresh svg{width:20px;height:20px;fill:var(--sc-text-light);transition:all var(--sc-transition)}.slider-captcha-refresh:hover{background:#f5f5f5;transform:scale(1.1)}.slider-captcha-refresh:hover svg{fill:var(--sc-primary);transform:rotate(180deg)}.slider-captcha-floating-time{position:absolute;bottom:-40px;left:50%;transform:translateX(-50%);color:#fff;font-size:12px;white-space:nowrap;opacity:0;pointer-events:none;z-index:10;transition:all var(--sc-transition);background:#fff;padding:2px 15px;border-radius:10px}.slider-captcha-floating-time.show{opacity:1;transform:translateX(-50%) translateY(-45px)}.slider-captcha-floating-time.success{color:var(--sc-success)}.slider-captcha-floating-time.fail{color:var(--sc-danger)}.slider-captcha-bg{width:100%;height:100%;object-fit:cover;display:block}.slider-captcha-piece{position:absolute;top:0;left:0;cursor:pointer;transition:none;z-index:2}.slider-captcha-finger{position:absolute;top:50%;left:10px;transform:translateY(-50%);font-size:20px;animation:fingerSlide 2s ease-in-out infinite;pointer-events:none;z-index:1;opacity:.6}.slider-captcha-hint{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:var(--sc-text-light);font-size:14px;pointer-events:none;z-index:1;transition:all var(--sc-transition)}.slider-captcha-header-buttons{display:flex;align-items:center}@keyframes fingerSlide{0%{left:10px;opacity:.6}50%{opacity:1}100%{left:calc(50% - 10px);opacity:.6}}"}static CONSTANTS={CACHE_DURATION:3e5,MAX_RETRY_ATTEMPTS:3,DEFAULT_TIMEOUT:3e4,FLOATING_TIME_DURATION:2500,THROTTLE_DELAY:16};static ERROR_TYPES={NETWORK_ERROR:"NETWORK_ERROR",TIMEOUT_ERROR:"TIMEOUT_ERROR",VALIDATION_ERROR:"VALIDATION_ERROR",IMAGE_LOAD_ERROR:"IMAGE_LOAD_ERROR",CAPTCHA_DATA_ERROR:"CAPTCHA_DATA_ERROR"};constructor(t={}){this.options={...PopupSliderCaptcha.DEFAULTS,...t,timeout:t.timeout||PopupSliderCaptcha.CONSTANTS.DEFAULT_TIMEOUT,maxRetries:t.maxRetries||PopupSliderCaptcha.CONSTANTS.MAX_RETRY_ATTEMPTS,throttleDelay:t.throttleDelay||PopupSliderCaptcha.CONSTANTS.THROTTLE_DELAY},this.elements={},this.state=this.createInitialState(),this.captchaData=null,this.times=[],this.startTime=null,this.eventListeners=[],this.timers=new Set,this.rafId=null,this.cachedDimensions=null,this.imageCache=new Map,this.abortController=null,this.throttledHandleMove=this.throttle(t=>this.handleMove(t),this.options.throttleDelay);try{this.init()}catch(t){this.handleError(PopupSliderCaptcha.ERROR_TYPES.VALIDATION_ERROR,t.message)}}createInitialState(){return{isVisible:!1,isDragging:!1,currentX:0,startX:0,retryCount:0,isLoading:!1}}init(){this.injectStyles(),this.createElements(),this.bindEvents()}injectStyles(){if(document.querySelector("#slider-captcha-styles"))return;const t=document.createElement("style");t.id="slider-captcha-styles",t.textContent=PopupSliderCaptcha.getStyles(),document.head.appendChild(t)}createElements(){const{elements:t,options:e}=this;[["overlay","div",PopupSliderCaptcha.CSS_CLASSES.overlay],["modal","div",PopupSliderCaptcha.CSS_CLASSES.modal],["header","div",PopupSliderCaptcha.CSS_CLASSES.header],["title","h3","slider-captcha-title","安全验证"],["closeBtn","button","slider-captcha-close"],["refreshBtn","button","slider-captcha-refresh"],["container","div",PopupSliderCaptcha.CSS_CLASSES.container],["backgroundImg","img","slider-captcha-bg"],["sliderImg","img","slider-captcha-piece"],["loadingText","div",PopupSliderCaptcha.CSS_CLASSES.loading,"加载中..."],["floatingTime","div","slider-captcha-floating-time"],["track","div",PopupSliderCaptcha.CSS_CLASSES.track],["fingerAnimation","div","slider-captcha-finger","👉"],["btn","div",PopupSliderCaptcha.CSS_CLASSES.btn],["icon","div","","→"],["hint","div",PopupSliderCaptcha.CSS_CLASSES.hint,"向右滑动完成验证"],["error","div",PopupSliderCaptcha.CSS_CLASSES.error]].forEach(([e,s,i,a])=>{t[e]=this.createElement(s,i,a)}),t.container.style.cssText=`width:${e.width}px;height:${e.height}px`,t.refreshBtn.innerHTML='<svg viewBox="0 0 24 24"><path d="M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z"/></svg>',this.assembleDOM(),this.setInitialState()}createElement(t,e="",s=""){const i=document.createElement(t);return e&&(i.className=e),s&&(i.textContent=s),i}assembleDOM(){const{elements:t}=this,e=this.createElement("div","slider-captcha-header-buttons");e.append(t.refreshBtn,t.closeBtn),t.header.append(t.title,e),t.container.append(t.backgroundImg,t.sliderImg,t.loadingText,t.floatingTime),t.btn.appendChild(t.icon),t.track.append(t.fingerAnimation,t.btn,t.hint),t.modal.append(t.header,t.container,t.track,t.error),t.overlay.appendChild(t.modal),document.body.appendChild(t.overlay)}setInitialState(){Object.assign(this.elements.container.style,{display:"none"}),Object.assign(this.elements.track.style,{display:"none"})}bindEvents(){const{elements:t}=this;this.addEventListener(t.closeBtn,"click",()=>this.hide()),this.addEventListener(t.refreshBtn,"click",()=>this.refresh()),this.addEventListener(t.overlay,"click",e=>{e.target===t.overlay&&this.options.clickMaskClose&&this.hide()}),this.addEventListener(document,"keydown",t=>{"Escape"===t.key&&this.state.isVisible&&this.hide()}),this.addEventListener(document,"visibilitychange",()=>this.handleVisibilityChange()),this.bindSliderEvents()}bindSliderEvents(){const{elements:t}=this,e={start:t=>this.handleStart(t),move:this.throttledHandleMove,end:()=>this.handleEnd()};this.addEventListener(t.btn,"mousedown",e.start),this.addEventListener(t.btn,"touchstart",e.start),this.addEventListener(t.sliderImg,"mousedown",e.start),this.addEventListener(t.sliderImg,"touchstart",e.start),this.addEventListener(document,"mousemove",e.move,{passive:!1}),this.addEventListener(document,"touchmove",e.move,{passive:!1}),this.addEventListener(document,"mouseup",e.end),this.addEventListener(document,"touchend",e.end)}addEventListener(t,e,s,i={}){t&&"function"==typeof s&&(t.addEventListener(e,s,i),this.eventListeners.push({element:t,event:e,handler:s,options:i}))}removeAllEventListeners(){this.eventListeners.forEach(({element:t,event:e,handler:s,options:i})=>{try{t?.removeEventListener?.(e,s,i)}catch(t){}}),this.eventListeners.length=0}getDimensions(){if(!this.cachedDimensions){const t=this.elements.track.offsetWidth,e=this.elements.btn.offsetWidth;this.cachedDimensions={trackWidth:t,btnWidth:e,maxX:t-e}}return this.cachedDimensions}getPosition(){const{maxX:t}=this.getDimensions(),e=this.state.currentX/t;return Math.round(e*(this.options.width-this.options.sliderSize))}handleStart(t){!this.captchaData||this.state.isDragging||this.state.isLoading||(t.preventDefault(),this.state.isDragging=!0,this.state.startX=this.getClientX(t)-this.state.currentX,this.dragStartTime=Date.now(),this.times=[{time:Date.now(),position:this.getPosition()}],this.setTransition(!1),this.updateUIState("dragging"),this.cachedDimensions=null)}handleMove(t){if(!this.state.isDragging)return;t.preventDefault();const e=this.getClientX(t)-this.state.startX,{maxX:s}=this.getDimensions();this.state.currentX=Math.max(0,Math.min(e,s)),this.times.push({time:Date.now(),position:this.getPosition()}),this.rafId&&cancelAnimationFrame(this.rafId),this.rafId=requestAnimationFrame(()=>this.updateSliderPosition())}handleEnd(){this.state.isDragging&&(this.times.push({time:Date.now(),position:this.getPosition()}),this.state.isDragging=!1,this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null),this.verify())}handleVisibilityChange(){const t=document.hidden?"paused":"running";this.elements.fingerAnimation&&(this.elements.fingerAnimation.style.animationPlayState=t)}getClientX(t){return t.type.includes("touch")?t.touches[0].clientX:t.clientX}setTransition(t){const e=t?"all 0.3s ease":"none";requestAnimationFrame(()=>{this.elements.btn.style.transition=e,this.elements.sliderImg.style.transition=e})}updateUIState(t){const{elements:e}=this,s={dragging:()=>{e.hint.style.opacity="0",e.fingerAnimation.style.display="none"},success:()=>{Object.assign(e.btn.style,{background:"var(--sc-success)"}),Object.assign(e.icon.style,{innerHTML:"✓",color:"white"}),e.icon.innerHTML="✓"},fail:()=>{Object.assign(e.btn.style,{background:"var(--sc-danger)"}),Object.assign(e.icon.style,{innerHTML:"✗",color:"white"}),e.icon.innerHTML="✗"},reset:()=>{Object.assign(e.btn.style,{background:"white"}),Object.assign(e.icon.style,{color:"#666"}),e.icon.innerHTML="→",e.fingerAnimation.style.display="block",this.updateHintText("向右滑动完成验证","var(--sc-text-light)")},loading:()=>{e.hint.style.opacity="0",e.fingerAnimation.style.display="none",Object.assign(e.track.style,{pointerEvents:"none",opacity:"0.6"})}};s[t]&&requestAnimationFrame(()=>{s[t](),"loading"!==t&&Object.assign(e.track.style,{pointerEvents:"auto",opacity:"1"})})}updateHintText(t,e){requestAnimationFrame(()=>{Object.assign(this.elements.hint,{textContent:t}),Object.assign(this.elements.hint.style,{color:e,opacity:"1"})})}updateSliderPosition(){const{elements:t,options:e,state:s}=this,{maxX:i}=this.getDimensions(),a=s.currentX/i*(e.width-e.sliderSize),n=s.currentX/i;requestAnimationFrame(()=>{t.btn.style.transform=`translateX(${s.currentX}px)`,t.sliderImg.style.transform=`translateX(${a}px)`,t.fingerAnimation.style.opacity=.8>n?"0.6":"0"})}show(){this.state.isVisible=!0,this.elements.overlay.style.display="flex",requestAnimationFrame(()=>{this.elements.overlay.classList.add("show"),this.elements.modal.classList.add("show")}),this.loadCaptcha()}hide(){this.state.isVisible=!1,this.elements.overlay.classList.remove("show"),this.elements.modal.classList.remove("show"),this.safeSetTimeout(()=>{this.elements.overlay.style.display="none",document.body.removeChild(this.elements.overlay),this.reset(),this.options.onClose?.(),this.elements.overlay=null},300)}handleError(t,e,s=null){const i={[PopupSliderCaptcha.ERROR_TYPES.NETWORK_ERROR]:"网络连接失败,请检查网络设置",[PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR]:"请求超时,请重试",[PopupSliderCaptcha.ERROR_TYPES.VALIDATION_ERROR]:"验证失败,请重试",[PopupSliderCaptcha.ERROR_TYPES.IMAGE_LOAD_ERROR]:"图片加载失败,请刷新重试",[PopupSliderCaptcha.ERROR_TYPES.CAPTCHA_DATA_ERROR]:"验证码数据错误,请刷新重试"}[t]||e||"未知错误";this.options.onError&&this.options.onError({type:t,message:i,originalError:s}),this.showError(i)}async loadCaptcha(){try{this.showLoading(),this.startTime=Date.now(),this.abortController&&this.abortController.abort(),this.abortController=new AbortController;const t=await fetch(this.options.apiUrl,{method:"POST",headers:{"Content-Type":"application/json",...this.options.headers},body:JSON.stringify({timestamp:Date.now(),...this.options.requestData}),signal:this.abortController.signal});if(!t.ok)throw Error(`HTTP ${t.status}: ${t.statusText}`);const e=await t.json();if(!this.validateCaptchaData(e))throw Error("验证码数据格式错误");this.captchaData=e.data,this.showCaptcha(),await this.renderCaptcha()}catch(t){"AbortError"===t.name?this.handleError(PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR,"请求被取消"):t.message.includes("Failed to fetch")||t.message.includes("NetworkError")?this.handleError(PopupSliderCaptcha.ERROR_TYPES.NETWORK_ERROR,"网络连接失败"):this.handleError(PopupSliderCaptcha.ERROR_TYPES.CAPTCHA_DATA_ERROR,t.message,t)}}validateCaptchaData(t){if(!t||"object"!=typeof t)return!1;const e=t.data||t;return["canvasSrc","blockSrc","canvasWidth","canvasHeight","blockWidth","blockHeight","blockY","nonceStr"].every(t=>{const s=e[t];return null!=s&&""!==s})}async renderCaptcha(){return new Promise((t,e)=>{let s=!1;const i=[this.loadImageAsync(this.elements.backgroundImg,this.captchaData.canvasSrc,{width:this.captchaData.canvasWidth,height:this.captchaData.canvasHeight}),this.loadImageAsync(this.elements.sliderImg,this.captchaData.blockSrc,{width:this.captchaData.blockWidth,height:this.captchaData.blockHeight,top:this.captchaData.blockY})];Promise.all(i).then(()=>{s||(this.hideLoading(),t())}).catch(t=>{s||(s=!0,this.handleError(PopupSliderCaptcha.ERROR_TYPES.IMAGE_LOAD_ERROR,"图片加载失败",t),e(t))})})}async loadImageAsync(t,e,s){return new Promise((i,a)=>{if(this.imageCache.has(e)){const a=this.imageCache.get(e);return t.src=a.src,this.applyStyles(t,s),void i()}const n=this.safeSetTimeout(()=>{a(Error("图片加载超时"))},1e4);t.onload=function(){this.safeClearTimeout(n),this.imageCache.set(e,t.cloneNode()),i()}.bind(this),t.onerror=function(t){this.safeClearTimeout(n),a(t)}.bind(this),t.src=e,this.applyStyles(t,s)})}applyStyles(t,e){Object.entries(e).forEach(([e,s])=>{t.style[e]="number"==typeof s?s+"px":s})}showLoading(){this.state.isLoading=!0,this.batchUpdateStyles({container:{display:"block"},loadingText:{display:"flex"},error:{display:"none"}}),this.updateUIState("loading")}hideLoading(){this.state.isLoading=!1,this.batchUpdateStyles({loadingText:{display:"none"}}),this.updateUIState("reset")}showCaptcha(){this.batchUpdateStyles({container:{display:"block"},track:{display:"block"},error:{display:"none"}})}showError(t){this.hideLoading(),this.batchUpdateStyles({error:{display:"block",textContent:t}})}batchUpdateStyles(t){requestAnimationFrame(()=>{Object.entries(t).forEach(([t,e])=>{const s=this.elements[t];s&&Object.entries(e).forEach(([t,e])=>{"textContent"===t?s.textContent=e:s.style[t]=e})})})}async verify(){if(this.captchaData)try{this.abortController&&this.abortController.abort(),this.abortController=new AbortController;const t=await fetch(this.options.verifyUrl,{method:"POST",headers:{"Content-Type":"application/json",...this.options.headers},body:JSON.stringify({loginVo:{nonceStr:this.captchaData.nonceStr,value:this.getPosition()},dragEventList:[...this.times],...this.options.verifyData}),signal:this.abortController.signal});if(!t.ok)throw Error(`HTTP ${t.status}: ${t.statusText}`);const e=await t.json();this.isVerifySuccess(e)?this.onVerifySuccess(e.data||e.result):this.onVerifyFail(e.message||e.msg||"验证失败,请重试!")}catch(t){"AbortError"===t.name?this.handleError(PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR,"验证请求被取消"):t.message.includes("Failed to fetch")||t.message.includes("NetworkError")?this.handleError(PopupSliderCaptcha.ERROR_TYPES.NETWORK_ERROR,"网络连接失败"):this.handleError(PopupSliderCaptcha.ERROR_TYPES.VALIDATION_ERROR,t.message,t)}else this.onVerifyFail("验证码数据丢失")}isVerifySuccess(t){return!(!t||"object"!=typeof t)&&["0"===t.code,0===t.code,!0===t.success,"success"===t.status,!0===t.result].some(t=>!0===t)}onVerifySuccess(t){const e=this.dragStartTime?Date.now()-this.dragStartTime:Date.now()-this.startTime,s=`验证成功!耗时:${(e/1e3).toFixed(2)}s`;this.updateUIState("success"),this.showFloatingTime(s,"success"),this.safeSetTimeout(()=>{this.options.onSuccess?.({ticket:t,timestamp:Date.now(),duration:e}),this.hide()},2e3)}showFloatingTime(t,e="success"){const{elements:s}=this;s.floatingTime.textContent=t,s.floatingTime.className="slider-captcha-floating-time "+e,this.safeSetTimeout(()=>s.floatingTime.classList.add("show"),100),this.safeSetTimeout(()=>{s.floatingTime.className="slider-captcha-floating-time"},2500)}onVerifyFail(t){this.state.retryCount++,this.updateUIState("fail"),this.showFloatingTime(t,"fail"),this.safeSetTimeout(()=>{this.state.retryCount<this.options.maxRetries?this.reset():this.refresh()},2500)}reset(){this.clearAllTimers(),Object.assign(this.state,{isDragging:!1,currentX:0,startX:0,isLoading:!1}),this.times=[],this.startTime=null,this.dragStartTime=null,this.cachedDimensions=null,requestAnimationFrame(()=>{this.setTransition(!0),this.elements.btn.style.transform="translateX(0px)",this.elements.sliderImg.style.transform="translateX(0px)",this.updateUIState("reset"),this.elements.error.style.display="none"})}refresh(){this.reset(),this.state.retryCount=0,this.loadCaptcha()}safeSetTimeout(t,e){const s=setTimeout(()=>{this.timers.delete(s),t()},e);return this.timers.add(s),s}safeClearTimeout(t){t&&(clearTimeout(t),this.timers.delete(t))}clearAllTimers(){this.timers.forEach(t=>{clearTimeout(t),clearInterval(t)}),this.timers.clear(),this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null)}cleanupImages(){this.elements.backgroundImg&&(this.elements.backgroundImg.src="",this.elements.backgroundImg.onload=null,this.elements.backgroundImg.onerror=null),this.elements.sliderImg&&(this.elements.sliderImg.src="",this.elements.sliderImg.onload=null,this.elements.sliderImg.onerror=null),this.imageCache.clear()}throttle(t,e){let s=0;return(...i)=>{const a=Date.now();if(a-s>=e)return s=a,t.apply(this,i)}}destroy(){try{this.abortController&&(this.abortController.abort(),this.abortController=null),document.body&&(document.body.style.userSelect="",document.body.style.cursor=""),this.clearAllTimers(),this.removeAllEventListeners(),this.cleanupImages(),this.elements?.overlay?.parentNode&&this.elements.overlay.parentNode.removeChild(this.elements.overlay);const t=document.getElementById("slider-captcha-styles");t&&t.remove(),this.imageCache.clear(),this.cachedDimensions=null,Object.keys(this).forEach(t=>{"constructor"!==t&&(this[t]=null)}),this.options.onDestroy&&this.options.onDestroy()}catch(t){}}static create(t){return new PopupSliderCaptcha(t)}static show(t){const e=new PopupSliderCaptcha(t);return e.show(),e}}return"undefined"!=typeof module&&module.exports?(module.exports=PopupSliderCaptcha,module.exports.default=PopupSliderCaptcha):"function"==typeof define&&define.amd?define([],()=>PopupSliderCaptcha):"undefined"!=typeof window&&(window.PopupSliderCaptcha=PopupSliderCaptcha,window.SliderCaptcha=PopupSliderCaptcha),PopupSliderCaptcha});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slider-captcha-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20",
|
|
4
4
|
"description": "纯JavaScript滑块验证码SDK和密码校验工具,无依赖,支持多种模块格式",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.min.js",
|
|
@@ -40,7 +40,12 @@
|
|
|
40
40
|
"dev": "rollup -c -w",
|
|
41
41
|
"prepublishOnly": "npm run build:prod",
|
|
42
42
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
43
|
-
"lint": "eslint src
|
|
43
|
+
"lint": "eslint src",
|
|
44
|
+
"lint:fix": "eslint src --fix",
|
|
45
|
+
"lint:check": "eslint src --max-warnings 0",
|
|
46
|
+
"format": "eslint src --fix",
|
|
47
|
+
"format:check": "eslint src --max-warnings 0",
|
|
48
|
+
"check": "npm run lint:check && npm run build:prod",
|
|
44
49
|
"clean": "rm -rf dist"
|
|
45
50
|
},
|
|
46
51
|
"keywords": [
|
|
@@ -67,10 +72,12 @@
|
|
|
67
72
|
"node": ">=12.0.0"
|
|
68
73
|
},
|
|
69
74
|
"devDependencies": {
|
|
75
|
+
"@eslint/js": "^9.35.0",
|
|
70
76
|
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
71
77
|
"@rollup/plugin-terser": "^0.4.0",
|
|
72
|
-
"eslint": "^
|
|
78
|
+
"eslint": "^9.35.0",
|
|
73
79
|
"eslint-plugin-vue": "^9.0.0",
|
|
80
|
+
"globals": "^16.4.0",
|
|
74
81
|
"rollup": "^3.0.0",
|
|
75
82
|
"rollup-plugin-copy": "^3.4.0"
|
|
76
83
|
},
|