user-behavior-monitor 1.0.0 → 4.0.1
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/README.md +2 -29
- package/dist/user-behavior-monitor.common.js +423 -130
- package/dist/user-behavior-monitor.umd.js +423 -130
- package/dist/user-behavior-monitor.umd.min.js +1 -2
- package/package.json +3 -2
- package/src/components/UserBehaviorMonitor.vue +396 -115
- package/src/components/{UserBehaviorMonitor1.vue → UserBehaviorMonitor2.vue} +195 -68
- package/dist/user-behavior-monitor.common.js.map +0 -1
- package/dist/user-behavior-monitor.umd.js.map +0 -1
- package/dist/user-behavior-monitor.umd.min.js.map +0 -1
|
@@ -87,6 +87,22 @@ module.exports =
|
|
|
87
87
|
/************************************************************************/
|
|
88
88
|
/******/ ({
|
|
89
89
|
|
|
90
|
+
/***/ "0c60":
|
|
91
|
+
/***/ (function(module, exports, __webpack_require__) {
|
|
92
|
+
|
|
93
|
+
// style-loader: Adds some css to the DOM by adding a <style> tag
|
|
94
|
+
|
|
95
|
+
// load the styles
|
|
96
|
+
var content = __webpack_require__("d167");
|
|
97
|
+
if(content.__esModule) content = content.default;
|
|
98
|
+
if(typeof content === 'string') content = [[module.i, content, '']];
|
|
99
|
+
if(content.locals) module.exports = content.locals;
|
|
100
|
+
// add the styles to the DOM
|
|
101
|
+
var add = __webpack_require__("499e").default
|
|
102
|
+
var update = add("9677a646", content, true, {"sourceMap":false,"shadowMode":false});
|
|
103
|
+
|
|
104
|
+
/***/ }),
|
|
105
|
+
|
|
90
106
|
/***/ "2350":
|
|
91
107
|
/***/ (function(module, exports) {
|
|
92
108
|
|
|
@@ -436,18 +452,7 @@ function applyToTag (styleElement, obj) {
|
|
|
436
452
|
|
|
437
453
|
/***/ }),
|
|
438
454
|
|
|
439
|
-
/***/ "
|
|
440
|
-
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
441
|
-
|
|
442
|
-
"use strict";
|
|
443
|
-
/* harmony import */ var _node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_index_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_UserBehaviorMonitor_vue_vue_type_style_index_0_id_06a138e4_prod_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("d1b1");
|
|
444
|
-
/* harmony import */ var _node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_index_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_UserBehaviorMonitor_vue_vue_type_style_index_0_id_06a138e4_prod_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_index_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_UserBehaviorMonitor_vue_vue_type_style_index_0_id_06a138e4_prod_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__);
|
|
445
|
-
/* unused harmony reexport * */
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
/***/ }),
|
|
449
|
-
|
|
450
|
-
/***/ "9cfc":
|
|
455
|
+
/***/ "d167":
|
|
451
456
|
/***/ (function(module, exports, __webpack_require__) {
|
|
452
457
|
|
|
453
458
|
exports = module.exports = __webpack_require__("2350")(false);
|
|
@@ -455,26 +460,21 @@ exports = module.exports = __webpack_require__("2350")(false);
|
|
|
455
460
|
|
|
456
461
|
|
|
457
462
|
// module
|
|
458
|
-
exports.push([module.i, ".
|
|
463
|
+
exports.push([module.i, ".behavior-warning-dialog.el-dialog.el-dialog--center{text-align:left}", ""]);
|
|
459
464
|
|
|
460
465
|
// exports
|
|
461
466
|
|
|
462
467
|
|
|
463
468
|
/***/ }),
|
|
464
469
|
|
|
465
|
-
/***/ "
|
|
466
|
-
/***/ (function(module,
|
|
470
|
+
/***/ "d1a8":
|
|
471
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
467
472
|
|
|
468
|
-
|
|
473
|
+
"use strict";
|
|
474
|
+
/* harmony import */ var _node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_index_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_UserBehaviorMonitor_vue_vue_type_style_index_0_id_0335f60c_prod_lang_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("0c60");
|
|
475
|
+
/* harmony import */ var _node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_index_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_UserBehaviorMonitor_vue_vue_type_style_index_0_id_0335f60c_prod_lang_css__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_index_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_UserBehaviorMonitor_vue_vue_type_style_index_0_id_0335f60c_prod_lang_css__WEBPACK_IMPORTED_MODULE_0__);
|
|
476
|
+
/* unused harmony reexport * */
|
|
469
477
|
|
|
470
|
-
// load the styles
|
|
471
|
-
var content = __webpack_require__("9cfc");
|
|
472
|
-
if(content.__esModule) content = content.default;
|
|
473
|
-
if(typeof content === 'string') content = [[module.i, content, '']];
|
|
474
|
-
if(content.locals) module.exports = content.locals;
|
|
475
|
-
// add the styles to the DOM
|
|
476
|
-
var add = __webpack_require__("499e").default
|
|
477
|
-
var update = add("2c53b590", content, true, {"sourceMap":false,"shadowMode":false});
|
|
478
478
|
|
|
479
479
|
/***/ }),
|
|
480
480
|
|
|
@@ -503,12 +503,12 @@ if (typeof window !== 'undefined') {
|
|
|
503
503
|
// Indicate to webpack that this file can be concatenated
|
|
504
504
|
/* harmony default export */ var setPublicPath = (null);
|
|
505
505
|
|
|
506
|
-
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"
|
|
507
|
-
var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{ref:"behaviorMonitor",staticClass:"user-behavior-monitor"},[_c('el-dialog',{attrs:{"visible":_vm.showWarning,"show-close":false,"modal":true,"width":"30%","center":"","custom-class":"behavior-warning-dialog"
|
|
506
|
+
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"14550f6a-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/UserBehaviorMonitor.vue?vue&type=template&id=0335f60c
|
|
507
|
+
var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{ref:"behaviorMonitor",staticClass:"user-behavior-monitor"},[_c('el-dialog',{attrs:{"title":"提示","visible":_vm.showWarning,"show-close":false,"modal":true,"width":"30%","center":"","custom-class":"behavior-warning-dialog"},on:{"update:visible":function($event){_vm.showWarning=$event}}},[_c('span',[_vm._v(_vm._s(_vm.warningMessage))])])],1)}
|
|
508
508
|
var staticRenderFns = []
|
|
509
509
|
|
|
510
510
|
|
|
511
|
-
// CONCATENATED MODULE: ./src/components/UserBehaviorMonitor.vue?vue&type=template&id=
|
|
511
|
+
// CONCATENATED MODULE: ./src/components/UserBehaviorMonitor.vue?vue&type=template&id=0335f60c
|
|
512
512
|
|
|
513
513
|
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/UserBehaviorMonitor.vue?vue&type=script&lang=js
|
|
514
514
|
//
|
|
@@ -528,23 +528,15 @@ var staticRenderFns = []
|
|
|
528
528
|
//
|
|
529
529
|
//
|
|
530
530
|
//
|
|
531
|
-
//
|
|
532
|
-
//
|
|
533
|
-
//
|
|
534
|
-
//
|
|
535
|
-
//
|
|
536
|
-
//
|
|
537
|
-
//
|
|
538
|
-
//
|
|
539
531
|
|
|
540
532
|
/* harmony default export */ var UserBehaviorMonitorvue_type_script_lang_js = ({
|
|
541
533
|
name: 'UserBehaviorMonitor',
|
|
542
534
|
props: {
|
|
543
535
|
// WebSocket服务器地址
|
|
544
|
-
websocketUrl: {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
},
|
|
536
|
+
// websocketUrl: {
|
|
537
|
+
// type: String,
|
|
538
|
+
// required: true
|
|
539
|
+
// },
|
|
548
540
|
// 倒计时时长(分钟)
|
|
549
541
|
timeoutMinutes: {
|
|
550
542
|
type: Number,
|
|
@@ -558,39 +550,123 @@ var staticRenderFns = []
|
|
|
558
550
|
},
|
|
559
551
|
data() {
|
|
560
552
|
return {
|
|
561
|
-
mouseMoveThrottled:false,
|
|
562
|
-
|
|
553
|
+
mouseMoveThrottled: false,
|
|
554
|
+
socket: null,
|
|
563
555
|
countdownTimer: null,
|
|
564
556
|
warningTimer: null,
|
|
565
557
|
showWarning: false,
|
|
566
|
-
|
|
558
|
+
// warningMinutes
|
|
559
|
+
warningMessage: `您已${this.timeoutMinutes}分钟未操作,将在1分钟后自动退出`,
|
|
567
560
|
lastActivityTime: null,
|
|
568
|
-
isMonitoring: false
|
|
561
|
+
isMonitoring: false,
|
|
562
|
+
currentTimeoutMinutes: 10,
|
|
563
|
+
currentWarningMinutes: 1,
|
|
564
|
+
reconnectAttempts: 0,
|
|
565
|
+
maxReconnectAttempts: 3,
|
|
566
|
+
reconnectDelay: 3000,
|
|
567
|
+
isLocalDevelopment: this.checkIfLocalDevelopment()
|
|
569
568
|
};
|
|
570
569
|
},
|
|
571
570
|
mounted() {
|
|
572
|
-
|
|
573
|
-
this.
|
|
571
|
+
// 检查当前路由是否包含/login,如果不包含则初始化监控
|
|
572
|
+
if (!this.isLoginRoute()) {
|
|
573
|
+
this.initMonitor();
|
|
574
|
+
}
|
|
574
575
|
},
|
|
575
576
|
beforeDestroy() {
|
|
576
|
-
console.log('开始开始! beforeDestroy');
|
|
577
577
|
this.destroyMonitor();
|
|
578
578
|
},
|
|
579
|
+
watch: {
|
|
580
|
+
// 监听路由变化
|
|
581
|
+
'$route'(to, from) {
|
|
582
|
+
// 安全检查 from.href 是否存在
|
|
583
|
+
const isFromLogin = from.path.includes('/login') ||
|
|
584
|
+
(from.href && from.href.includes('/login'));
|
|
585
|
+
|
|
586
|
+
// 检查当前是否为登录路由
|
|
587
|
+
const isToLogin = this.isLoginRoute();
|
|
588
|
+
|
|
589
|
+
// 如果从登录页跳转到非登录页,且监控未启动,则初始化监控
|
|
590
|
+
if (isFromLogin && !isToLogin && !this.isMonitoring) {
|
|
591
|
+
this.initMonitor();
|
|
592
|
+
}
|
|
593
|
+
// 如果从非登录页跳转到登录页,且监控正在运行,则销毁监控
|
|
594
|
+
else if (!isFromLogin && isToLogin && this.isMonitoring) {
|
|
595
|
+
this.destroyMonitor();
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
},
|
|
579
599
|
methods: {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
600
|
+
// 检查当前路由是否为登录页面
|
|
601
|
+
isLoginRoute() {
|
|
602
|
+
// 优先检查 Vue Router 路由
|
|
603
|
+
if (this.$route && this.$route.path) {
|
|
604
|
+
if (this.$route.path.includes('/login')) {
|
|
605
|
+
return true;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// 检查浏览器地址栏作为后备
|
|
610
|
+
if (typeof window !== 'undefined') {
|
|
611
|
+
return window.location.pathname.includes('/login') ||
|
|
612
|
+
window.location.href.includes('/login');
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
return false;
|
|
616
|
+
},
|
|
617
|
+
|
|
618
|
+
// 检查是否为本地开发环境
|
|
619
|
+
checkIfLocalDevelopment() {
|
|
620
|
+
if (typeof window !== 'undefined') {
|
|
621
|
+
const hostname = window.location.hostname;
|
|
622
|
+
return hostname === 'localhost' ||
|
|
623
|
+
hostname === '127.0.0.1' ||
|
|
624
|
+
hostname === '0.0.0.0' ||
|
|
625
|
+
/^192\.168\./.test(hostname) || // 局域网IP
|
|
626
|
+
/^10\./.test(hostname) || // 局域网IP
|
|
627
|
+
/^172\.(1[6-9]|2[0-9]|3[01])\./.test(hostname); // 局域网IP
|
|
628
|
+
}
|
|
629
|
+
return false;
|
|
630
|
+
},
|
|
631
|
+
|
|
632
|
+
updateTimeoutSettings(timeoutMinutes, warningMinutes) {
|
|
633
|
+
if (timeoutMinutes !== undefined) {
|
|
634
|
+
this.currentTimeoutMinutes = timeoutMinutes;
|
|
635
|
+
localStorage.setItem('userBehavior_timeoutMinutes', timeoutMinutes.toString());
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if (warningMinutes !== undefined) {
|
|
639
|
+
this.currentWarningMinutes = warningMinutes;
|
|
640
|
+
localStorage.setItem('userBehavior_warningMinutes', warningMinutes.toString());
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// 更新警告消息
|
|
644
|
+
// ${this.currentWarningMinutes}
|
|
645
|
+
this.warningMessage = `您已${this.currentTimeoutMinutes}分钟未操作,将在1分钟后自动退出`;
|
|
646
|
+
|
|
647
|
+
// 重置计时器
|
|
648
|
+
this.resetTimer();
|
|
583
649
|
},
|
|
584
650
|
// 初始化监控
|
|
585
651
|
initMonitor() {
|
|
586
|
-
|
|
652
|
+
// 再次检查确保不在登录页面
|
|
653
|
+
if (this.isLoginRoute()) {
|
|
654
|
+
// 如果在登录页面,确保清理所有监控资源
|
|
655
|
+
this.destroyMonitor();
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
|
|
587
659
|
if (this.isMonitoring) return;
|
|
588
660
|
|
|
589
661
|
this.isMonitoring = true;
|
|
590
662
|
this.lastActivityTime = Date.now();
|
|
663
|
+
this.reconnectAttempts = 0; // 重置重连尝试次数
|
|
664
|
+
|
|
665
|
+
// 初始化WebSocket连接
|
|
666
|
+
this.initWebSocket();
|
|
591
667
|
|
|
592
668
|
// 启动倒计时
|
|
593
|
-
this.startCountdown();
|
|
669
|
+
// this.startCountdown();
|
|
594
670
|
|
|
595
671
|
// 绑定事件监听器
|
|
596
672
|
this.bindEventListeners();
|
|
@@ -604,71 +680,263 @@ var staticRenderFns = []
|
|
|
604
680
|
if (this.countdownTimer) clearInterval(this.countdownTimer);
|
|
605
681
|
if (this.warningTimer) clearTimeout(this.warningTimer);
|
|
606
682
|
|
|
683
|
+
// 关闭WebSocket连接
|
|
684
|
+
if (this.socket) {
|
|
685
|
+
this.socket.close();
|
|
686
|
+
this.socket = null;
|
|
687
|
+
}
|
|
688
|
+
|
|
607
689
|
// 解绑事件监听器
|
|
608
690
|
this.unbindEventListeners();
|
|
609
691
|
},
|
|
610
692
|
|
|
693
|
+
// 初始化WebSocket连接
|
|
694
|
+
initWebSocket() {
|
|
695
|
+
try {
|
|
696
|
+
// 使用传入的WebSocket URL
|
|
697
|
+
const websocketUrl = `wss://${location.host}/xy-api/auth-server/ws/user-activity`;
|
|
698
|
+
|
|
699
|
+
// 获取token(假设存储在localStorage中)
|
|
700
|
+
let token = '';
|
|
701
|
+
try {
|
|
702
|
+
const apiHeader = localStorage.getItem('api_header');
|
|
703
|
+
if (apiHeader) {
|
|
704
|
+
token = JSON.parse(apiHeader).Authorization || '';
|
|
705
|
+
}
|
|
706
|
+
} catch (e) {
|
|
707
|
+
token = localStorage.getItem('token') || '';
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// 创建WebSocket连接
|
|
711
|
+
this.socket = new WebSocket(`${websocketUrl}?token=${encodeURIComponent(token)}`);
|
|
712
|
+
|
|
713
|
+
// 设置连接成功回调
|
|
714
|
+
this.socket.onopen = () => {
|
|
715
|
+
console.log('WebSocket连接已建立');
|
|
716
|
+
this.sendUserBehavior();
|
|
717
|
+
this.$emit('websocket-open');
|
|
718
|
+
// 连接成功时重置重连尝试次数
|
|
719
|
+
this.reconnectAttempts = 0;
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
// 设置接收消息回调
|
|
723
|
+
this.socket.onmessage = (event) => {
|
|
724
|
+
try {
|
|
725
|
+
const data = JSON.parse(event.data);
|
|
726
|
+
console.log('收到用户活动状态消息:', data);
|
|
727
|
+
this.handleActivityStatus(data);
|
|
728
|
+
this.$emit('websocket-message', data);
|
|
729
|
+
} catch (e) {
|
|
730
|
+
console.error('解析WebSocket消息失败:', e);
|
|
731
|
+
}
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
// 设置连接关闭回调
|
|
735
|
+
this.socket.onclose = (event) => {
|
|
736
|
+
console.log('WebSocket连接已断开:', event.reason);
|
|
737
|
+
this.$emit('websocket-close');
|
|
738
|
+
|
|
739
|
+
// 如果不是在登录页面且监控仍在运行,尝试重连
|
|
740
|
+
if (this.shouldAttemptReconnect()) {
|
|
741
|
+
this.attemptReconnect();
|
|
742
|
+
} else if (!this.isLoginRoute() && this.isMonitoring) {
|
|
743
|
+
// 如果不应该重连但仍在监控状态,根据环境决定是否跳转
|
|
744
|
+
if (!this.isLocalDevelopment) {
|
|
745
|
+
this.handleReconnectFailure();
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
// 设置连接错误回调
|
|
751
|
+
this.socket.onerror = (error) => {
|
|
752
|
+
console.error('WebSocket错误:', error);
|
|
753
|
+
this.$emit('websocket-error', error);
|
|
754
|
+
|
|
755
|
+
// 如果不是在登录页面且监控仍在运行,尝试重连
|
|
756
|
+
if (this.shouldAttemptReconnect()) {
|
|
757
|
+
this.attemptReconnect();
|
|
758
|
+
} else if (!this.isLoginRoute() && this.isMonitoring) {
|
|
759
|
+
// 如果不应该重连但仍在监控状态,根据环境决定是否跳转
|
|
760
|
+
if (!this.isLocalDevelopment) {
|
|
761
|
+
this.handleReconnectFailure();
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
|
|
766
|
+
} catch (error) {
|
|
767
|
+
console.error('WebSocket初始化失败:', error);
|
|
768
|
+
this.$emit('websocket-error', error);
|
|
769
|
+
|
|
770
|
+
// 初始化失败时也可以尝试重连(如果不是在登录页面)
|
|
771
|
+
if (this.shouldAttemptReconnect()) {
|
|
772
|
+
this.attemptReconnect();
|
|
773
|
+
} else if (!this.isLoginRoute() && this.isMonitoring) {
|
|
774
|
+
// 如果不应该重连但仍在监控状态,根据环境决定是否跳转
|
|
775
|
+
if (!this.isLocalDevelopment) {
|
|
776
|
+
this.handleReconnectFailure();
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
},
|
|
781
|
+
|
|
782
|
+
// 判断是否应该尝试重连
|
|
783
|
+
shouldAttemptReconnect() {
|
|
784
|
+
return this.isMonitoring &&
|
|
785
|
+
!this.isLoginRoute() &&
|
|
786
|
+
this.reconnectAttempts < this.maxReconnectAttempts;
|
|
787
|
+
},
|
|
788
|
+
|
|
789
|
+
// 添加重连方法
|
|
790
|
+
attemptReconnect() {
|
|
791
|
+
// 再次检查是否为登录页面
|
|
792
|
+
if (this.isLoginRoute()) {
|
|
793
|
+
console.log('当前在登录页面,取消重连');
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
this.reconnectAttempts++;
|
|
798
|
+
console.log(`尝试第${this.reconnectAttempts}次重连...`);
|
|
799
|
+
|
|
800
|
+
// 如果是本地开发环境且重连次数已达到最大值,则不跳转登录页
|
|
801
|
+
if (this.isLocalDevelopment && this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
802
|
+
console.log('本地开发环境,重连失败但不跳转到登录页');
|
|
803
|
+
this.$emit('websocket-reconnect-failed');
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// 如果是线上环境且重连次数已达到最大值,则跳转到登录页
|
|
808
|
+
if (!this.isLocalDevelopment && this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
809
|
+
console.log('线上环境,重连失败,跳转到登录页');
|
|
810
|
+
this.handleReconnectFailure();
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
setTimeout(() => {
|
|
815
|
+
this.initWebSocket();
|
|
816
|
+
}, this.reconnectDelay);
|
|
817
|
+
},
|
|
818
|
+
|
|
819
|
+
// 处理重连失败
|
|
820
|
+
handleReconnectFailure() {
|
|
821
|
+
// 清空缓存
|
|
822
|
+
localStorage.clear();
|
|
823
|
+
sessionStorage.clear();
|
|
824
|
+
|
|
825
|
+
// 跳转到登录页
|
|
826
|
+
window.location.href = '/login';
|
|
827
|
+
|
|
828
|
+
// 触发登出事件
|
|
829
|
+
this.$emit('logout');
|
|
830
|
+
},
|
|
831
|
+
|
|
832
|
+
// 处理活动状态信息
|
|
833
|
+
handleActivityStatus(data) {
|
|
834
|
+
if (data.type === 'ACTIVITY_STATUS' && data.data) {
|
|
835
|
+
const activityData = data.data;
|
|
836
|
+
|
|
837
|
+
// 更新超时和警告时间配置
|
|
838
|
+
this.currentTimeoutMinutes = activityData.timeoutMinutes || 10;
|
|
839
|
+
this.currentWarningMinutes = activityData.reminderMinutes || 1;
|
|
840
|
+
|
|
841
|
+
// 更新警告消息
|
|
842
|
+
this.warningMessage = `您已${this.currentTimeoutMinutes}分钟未操作,将在${this.currentWarningMinutes}分钟后自动退出`;
|
|
843
|
+
if(activityData.needReminder){
|
|
844
|
+
this.showWarningWarning(activityData.remainingMillis);
|
|
845
|
+
}
|
|
846
|
+
// remainingMillis
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
// 检查是否仍然活跃
|
|
850
|
+
//if (!activityData.isActive) {
|
|
851
|
+
//this.handleInactiveStatus();
|
|
852
|
+
//}
|
|
853
|
+
}
|
|
854
|
+
// 检查是否需要显示提醒
|
|
855
|
+
// let dataReminder=data.data;
|
|
856
|
+
// if (dataReminder&&dataReminder.needReminder) {
|
|
857
|
+
// this.showWarningWarning(dataReminder.remainingSeconds);
|
|
858
|
+
// }
|
|
859
|
+
},
|
|
860
|
+
|
|
861
|
+
// 处理非活跃状态
|
|
862
|
+
handleInactiveStatus() {
|
|
863
|
+
// 清空缓存
|
|
864
|
+
localStorage.clear();
|
|
865
|
+
sessionStorage.clear();
|
|
866
|
+
|
|
867
|
+
// 跳转到登录页
|
|
868
|
+
//this.$router.push('/login');
|
|
869
|
+
|
|
870
|
+
// 或者使用window.location
|
|
871
|
+
window.location.href = '/login';
|
|
872
|
+
|
|
873
|
+
// 触发登出事件
|
|
874
|
+
this.$emit('logout');
|
|
875
|
+
},
|
|
876
|
+
|
|
611
877
|
// 发送用户行为数据到后端
|
|
612
878
|
sendUserBehavior(data) {
|
|
613
|
-
|
|
614
|
-
|
|
879
|
+
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
880
|
+
const message = {
|
|
881
|
+
"type": "HEARTBEAT",
|
|
882
|
+
"message": "心跳",
|
|
883
|
+
};
|
|
884
|
+
console.log('用户行为监测:', JSON.stringify(message));
|
|
885
|
+
this.socket.send(JSON.stringify(message));
|
|
886
|
+
}
|
|
615
887
|
},
|
|
616
888
|
|
|
617
889
|
// 绑定事件监听器
|
|
618
890
|
bindEventListeners() {
|
|
619
|
-
console.log('Binding event listeners');
|
|
620
|
-
// 使用箭头函数或bind来保持this上下文
|
|
621
891
|
// 鼠标事件
|
|
622
|
-
document.addEventListener('click', this.handleUserActivity
|
|
623
|
-
document.addEventListener('dblclick', this.handleUserActivity
|
|
624
|
-
document.addEventListener('mousedown', this.handleUserActivity
|
|
625
|
-
document.addEventListener('mouseup', this.handleUserActivity
|
|
626
|
-
document.addEventListener('mousemove', this.handleMouseMove
|
|
627
|
-
document.addEventListener('mouseover', this.handleUserActivity
|
|
628
|
-
document.addEventListener('mouseout', this.handleUserActivity
|
|
892
|
+
document.addEventListener('click', this.handleUserActivity, true);
|
|
893
|
+
document.addEventListener('dblclick', this.handleUserActivity, true);
|
|
894
|
+
document.addEventListener('mousedown', this.handleUserActivity, true);
|
|
895
|
+
document.addEventListener('mouseup', this.handleUserActivity, true);
|
|
896
|
+
document.addEventListener('mousemove', this.handleMouseMove, true);
|
|
897
|
+
document.addEventListener('mouseover', this.handleUserActivity, true);
|
|
898
|
+
document.addEventListener('mouseout', this.handleUserActivity, true);
|
|
629
899
|
|
|
630
900
|
// 键盘事件
|
|
631
|
-
document.addEventListener('keydown', this.handleUserActivity
|
|
632
|
-
document.addEventListener('keyup', this.handleUserActivity
|
|
901
|
+
document.addEventListener('keydown', this.handleUserActivity, true);
|
|
902
|
+
document.addEventListener('keyup', this.handleUserActivity, true);
|
|
633
903
|
|
|
634
904
|
// 表单事件
|
|
635
|
-
document.addEventListener('input', this.handleUserActivity
|
|
636
|
-
document.addEventListener('change', this.handleUserActivity
|
|
637
|
-
document.addEventListener('focus', this.handleUserActivity
|
|
638
|
-
document.addEventListener('blur', this.handleUserActivity
|
|
905
|
+
document.addEventListener('input', this.handleUserActivity, true);
|
|
906
|
+
document.addEventListener('change', this.handleUserActivity, true);
|
|
907
|
+
document.addEventListener('focus', this.handleUserActivity, true);
|
|
908
|
+
document.addEventListener('blur', this.handleUserActivity, true);
|
|
639
909
|
|
|
640
910
|
// 滚动事件(防抖处理)
|
|
641
|
-
document.addEventListener('scroll', this.debounce(this.handleUserActivity, 300)
|
|
911
|
+
document.addEventListener('scroll', this.debounce(this.handleUserActivity, 300), true);
|
|
642
912
|
|
|
643
913
|
// 窗口事件
|
|
644
|
-
window.addEventListener('resize', this.handleUserActivity
|
|
645
|
-
window.addEventListener('beforeunload', this.handleBeforeUnload
|
|
914
|
+
window.addEventListener('resize', this.handleUserActivity, true);
|
|
915
|
+
window.addEventListener('beforeunload', this.handleBeforeUnload);
|
|
646
916
|
},
|
|
647
917
|
|
|
648
918
|
// 解绑事件监听器
|
|
649
919
|
unbindEventListeners() {
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
document.removeEventListener('
|
|
653
|
-
document.removeEventListener('
|
|
654
|
-
document.removeEventListener('
|
|
655
|
-
document.removeEventListener('
|
|
656
|
-
document.removeEventListener('
|
|
657
|
-
|
|
658
|
-
document.removeEventListener('
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
document.removeEventListener('
|
|
662
|
-
|
|
663
|
-
document.removeEventListener('
|
|
664
|
-
document.removeEventListener('
|
|
665
|
-
|
|
666
|
-
document.removeEventListener('
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
window.removeEventListener('resize', this.handleUserActivity.bind(this), true);
|
|
671
|
-
window.removeEventListener('beforeunload', this.handleBeforeUnload.bind(this));
|
|
920
|
+
document.removeEventListener('click', this.handleUserActivity, true);
|
|
921
|
+
document.removeEventListener('dblclick', this.handleUserActivity, true);
|
|
922
|
+
document.removeEventListener('mousedown', this.handleUserActivity, true);
|
|
923
|
+
document.removeEventListener('mouseup', this.handleUserActivity, true);
|
|
924
|
+
document.removeEventListener('mousemove', this.handleMouseMove, true);
|
|
925
|
+
document.removeEventListener('mouseover', this.handleUserActivity, true);
|
|
926
|
+
document.removeEventListener('mouseout', this.handleUserActivity, true);
|
|
927
|
+
|
|
928
|
+
document.removeEventListener('keydown', this.handleUserActivity, true);
|
|
929
|
+
document.removeEventListener('keyup', this.handleUserActivity, true);
|
|
930
|
+
|
|
931
|
+
document.removeEventListener('input', this.handleUserActivity, true);
|
|
932
|
+
document.removeEventListener('change', this.handleUserActivity, true);
|
|
933
|
+
document.removeEventListener('focus', this.handleUserActivity, true);
|
|
934
|
+
document.removeEventListener('blur', this.handleUserActivity, true);
|
|
935
|
+
|
|
936
|
+
document.removeEventListener('scroll', this.debounce(this.handleUserActivity, 300), true);
|
|
937
|
+
|
|
938
|
+
window.removeEventListener('resize', this.handleUserActivity, true);
|
|
939
|
+
window.removeEventListener('beforeunload', this.handleBeforeUnload);
|
|
672
940
|
},
|
|
673
941
|
|
|
674
942
|
// 处理用户活动
|
|
@@ -699,7 +967,7 @@ var staticRenderFns = []
|
|
|
699
967
|
|
|
700
968
|
this.sendUserBehavior(behaviorData);
|
|
701
969
|
},
|
|
702
|
-
|
|
970
|
+
handleMouseMove(event) {
|
|
703
971
|
if (!this.mouseMoveThrottled) {
|
|
704
972
|
this.handleUserActivity(event);
|
|
705
973
|
this.mouseMoveThrottled = true;
|
|
@@ -709,20 +977,6 @@ var staticRenderFns = []
|
|
|
709
977
|
}
|
|
710
978
|
},
|
|
711
979
|
|
|
712
|
-
// 处理鼠标移动(降低频率)
|
|
713
|
-
// handleMouseMove: function() {
|
|
714
|
-
// let isThrottled = false;
|
|
715
|
-
// return (event) => {
|
|
716
|
-
// if (!isThrottled) {
|
|
717
|
-
// this.handleUserActivity(event);
|
|
718
|
-
// isThrottled = true;
|
|
719
|
-
// setTimeout(() => {
|
|
720
|
-
// isThrottled = false;
|
|
721
|
-
// }, 500);
|
|
722
|
-
// }
|
|
723
|
-
// };
|
|
724
|
-
// }(),
|
|
725
|
-
|
|
726
980
|
// 判断是否为自动触发事件
|
|
727
981
|
isAutomaticEvent(event) {
|
|
728
982
|
// 自动刷新等非用户主动触发的事件
|
|
@@ -747,9 +1001,9 @@ var staticRenderFns = []
|
|
|
747
1001
|
|
|
748
1002
|
// 重置计时器
|
|
749
1003
|
resetTimer() {
|
|
750
|
-
console.log('Resetting timer');
|
|
751
1004
|
this.lastActivityTime = Date.now();
|
|
752
1005
|
this.showWarning = false;
|
|
1006
|
+
this.reconnectAttempts = 0; // 重置重连尝试次数
|
|
753
1007
|
|
|
754
1008
|
// 清除警告定时器
|
|
755
1009
|
if (this.warningTimer) {
|
|
@@ -758,52 +1012,48 @@ var staticRenderFns = []
|
|
|
758
1012
|
}
|
|
759
1013
|
|
|
760
1014
|
// 重新启动倒计时
|
|
761
|
-
this.startCountdown();
|
|
1015
|
+
// this.startCountdown();
|
|
762
1016
|
|
|
763
1017
|
this.$emit('user-active');
|
|
764
1018
|
},
|
|
765
1019
|
|
|
766
1020
|
// 启动倒计时
|
|
767
1021
|
startCountdown() {
|
|
768
|
-
console.log('Starting countdown');
|
|
769
1022
|
// 清除现有定时器
|
|
770
1023
|
if (this.countdownTimer) clearInterval(this.countdownTimer);
|
|
771
1024
|
|
|
772
1025
|
// 设置新的倒计时
|
|
773
1026
|
this.countdownTimer = setInterval(() => {
|
|
774
1027
|
const now = Date.now();
|
|
775
|
-
const elapsedMinutes = (now - this.lastActivityTime) / (1000 *
|
|
776
|
-
console.log('Elapsed minutes:', elapsedMinutes);
|
|
1028
|
+
const elapsedMinutes = (now - this.lastActivityTime) / (1000 * 50);
|
|
777
1029
|
|
|
778
1030
|
// 检查是否需要显示警告
|
|
779
|
-
if (elapsedMinutes >= (this.
|
|
780
|
-
console.log('Showing warning');
|
|
1031
|
+
if (elapsedMinutes >= (this.currentTimeoutMinutes - this.currentWarningMinutes) && !this.warningTimer) {
|
|
781
1032
|
this.showWarningWarning();
|
|
782
1033
|
}
|
|
783
1034
|
|
|
784
1035
|
// 检查是否超时
|
|
785
|
-
if (elapsedMinutes >= this.
|
|
786
|
-
console.log('Handling timeout');
|
|
1036
|
+
if (elapsedMinutes >= this.currentTimeoutMinutes) {
|
|
787
1037
|
this.handleTimeout();
|
|
788
1038
|
}
|
|
789
1039
|
}, 1000);
|
|
790
1040
|
},
|
|
791
1041
|
|
|
792
1042
|
// 显示超时警告
|
|
793
|
-
showWarningWarning() {
|
|
1043
|
+
showWarningWarning(timeoutMinutes) {
|
|
1044
|
+
let time=timeoutMinutes||50000;
|
|
794
1045
|
console.log('Setting showWarning to true');
|
|
795
1046
|
this.showWarning = true;
|
|
796
1047
|
this.$emit('timeout-warning');
|
|
797
|
-
|
|
1048
|
+
if (this.warningTimer) clearTimeout(this.warningTimer);
|
|
798
1049
|
// 设置超时处理
|
|
799
1050
|
this.warningTimer = setTimeout(() => {
|
|
800
1051
|
this.handleTimeout();
|
|
801
|
-
},
|
|
1052
|
+
}, time);
|
|
802
1053
|
},
|
|
803
1054
|
|
|
804
1055
|
// 处理超时
|
|
805
1056
|
handleTimeout() {
|
|
806
|
-
console.log('Handling timeout');
|
|
807
1057
|
this.showWarning = false;
|
|
808
1058
|
this.$emit('timeout');
|
|
809
1059
|
|
|
@@ -813,9 +1063,24 @@ var staticRenderFns = []
|
|
|
813
1063
|
|
|
814
1064
|
// 登出操作
|
|
815
1065
|
logout() {
|
|
816
|
-
|
|
817
|
-
|
|
1066
|
+
localStorage.clear();
|
|
1067
|
+
sessionStorage.clear();
|
|
1068
|
+
location.reload();
|
|
1069
|
+
// 跳转到登录页
|
|
1070
|
+
//this.$router.push('/login');
|
|
818
1071
|
|
|
1072
|
+
// 或者使用window.location
|
|
1073
|
+
// window.location.href = '/login';
|
|
1074
|
+
// 发送登出消息到后端
|
|
1075
|
+
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
1076
|
+
const message = {
|
|
1077
|
+
type: 'logout',
|
|
1078
|
+
timestamp: Date.now()
|
|
1079
|
+
};
|
|
1080
|
+
this.socket.send(JSON.stringify(message));
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// 触发登出事件
|
|
819
1084
|
this.$emit('logout');
|
|
820
1085
|
|
|
821
1086
|
// 清除定时器
|
|
@@ -825,21 +1090,50 @@ var staticRenderFns = []
|
|
|
825
1090
|
|
|
826
1091
|
// 处理页面卸载前的操作
|
|
827
1092
|
handleBeforeUnload(event) {
|
|
828
|
-
//
|
|
829
|
-
|
|
1093
|
+
// 发送页面关闭消息
|
|
1094
|
+
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
1095
|
+
const message = {
|
|
1096
|
+
type: 'page_unload',
|
|
1097
|
+
timestamp: Date.now()
|
|
1098
|
+
};
|
|
1099
|
+
this.socket.send(JSON.stringify(message));
|
|
1100
|
+
}
|
|
830
1101
|
},
|
|
831
1102
|
|
|
832
1103
|
// 手动重置监控
|
|
833
1104
|
reset() {
|
|
1105
|
+
// 检查当前路由,如果在登录页面则销毁监控
|
|
1106
|
+
if (this.isLoginRoute()) {
|
|
1107
|
+
this.destroyMonitor();
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
834
1111
|
this.resetTimer();
|
|
1112
|
+
},
|
|
1113
|
+
|
|
1114
|
+
// 重新连接WebSocket
|
|
1115
|
+
reconnect() {
|
|
1116
|
+
// 检查当前路由,如果在登录页面则销毁监控
|
|
1117
|
+
if (this.isLoginRoute()) {
|
|
1118
|
+
this.destroyMonitor();
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
// 重置重连尝试次数
|
|
1123
|
+
this.reconnectAttempts = 0;
|
|
1124
|
+
|
|
1125
|
+
if (this.socket) {
|
|
1126
|
+
this.socket.close();
|
|
1127
|
+
}
|
|
1128
|
+
this.initWebSocket();
|
|
835
1129
|
}
|
|
836
1130
|
}
|
|
837
1131
|
});
|
|
838
1132
|
|
|
839
1133
|
// CONCATENATED MODULE: ./src/components/UserBehaviorMonitor.vue?vue&type=script&lang=js
|
|
840
1134
|
/* harmony default export */ var components_UserBehaviorMonitorvue_type_script_lang_js = (UserBehaviorMonitorvue_type_script_lang_js);
|
|
841
|
-
// EXTERNAL MODULE: ./src/components/UserBehaviorMonitor.vue?vue&type=style&index=0&id=
|
|
842
|
-
var
|
|
1135
|
+
// EXTERNAL MODULE: ./src/components/UserBehaviorMonitor.vue?vue&type=style&index=0&id=0335f60c&prod&lang=css
|
|
1136
|
+
var UserBehaviorMonitorvue_type_style_index_0_id_0335f60c_prod_lang_css = __webpack_require__("d1a8");
|
|
843
1137
|
|
|
844
1138
|
// CONCATENATED MODULE: ./node_modules/vue-loader/lib/runtime/componentNormalizer.js
|
|
845
1139
|
/* globals __VUE_SSR_CONTEXT__ */
|
|
@@ -954,7 +1248,7 @@ var component = normalizeComponent(
|
|
|
954
1248
|
staticRenderFns,
|
|
955
1249
|
false,
|
|
956
1250
|
null,
|
|
957
|
-
|
|
1251
|
+
null,
|
|
958
1252
|
null
|
|
959
1253
|
|
|
960
1254
|
)
|
|
@@ -987,5 +1281,4 @@ if (typeof window !== 'undefined' && window.Vue) {
|
|
|
987
1281
|
|
|
988
1282
|
/***/ })
|
|
989
1283
|
|
|
990
|
-
/******/ });
|
|
991
|
-
//# sourceMappingURL=user-behavior-monitor.common.js.map
|
|
1284
|
+
/******/ });
|