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