user-behavior-monitor 1.0.0 → 2.0.0
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 +311 -120
- package/dist/user-behavior-monitor.common.js.map +1 -1
- package/dist/user-behavior-monitor.umd.js +311 -120
- package/dist/user-behavior-monitor.umd.js.map +1 -1
- package/dist/user-behavior-monitor.umd.min.js +1 -1
- package/dist/user-behavior-monitor.umd.min.js.map +1 -1
- package/package.json +3 -2
- package/src/components/UserBehaviorMonitor.vue +293 -115
- package/src/components/{UserBehaviorMonitor1.vue → UserBehaviorMonitor2.vue} +130 -60
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "user-behavior-monitor",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Vue component for monitoring user behavior and auto-logout",
|
|
5
5
|
"main": "dist/user-behavior-monitor.umd.min.js",
|
|
6
6
|
"files": [
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"prepublishOnly": "npm run build"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"element-ui": "^2.15.0"
|
|
15
|
+
"element-ui": "^2.15.0",
|
|
16
|
+
"socket.io-client": "^4.8.1"
|
|
16
17
|
},
|
|
17
18
|
"peerDependencies": {
|
|
18
19
|
"vue": "^2.5.2"
|
|
@@ -2,24 +2,16 @@
|
|
|
2
2
|
<div ref="behaviorMonitor" class="user-behavior-monitor">
|
|
3
3
|
<!-- 提示框 -->
|
|
4
4
|
<el-dialog
|
|
5
|
+
title="提示"
|
|
5
6
|
:visible.sync="showWarning"
|
|
6
7
|
:show-close="false"
|
|
7
8
|
:modal="true"
|
|
8
9
|
width="30%"
|
|
9
10
|
center
|
|
10
11
|
custom-class="behavior-warning-dialog"
|
|
11
|
-
:append-to-body="true"
|
|
12
|
-
:modal-append-to-body="true"
|
|
13
|
-
:close-on-click-modal="false"
|
|
14
|
-
:close-on-press-escape="false"
|
|
15
12
|
>
|
|
16
13
|
<span>{{ warningMessage }}</span>
|
|
17
14
|
</el-dialog>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<button @click="testWarning" style="position: fixed; top: 10px; right: 10px; z-index: 10000;">
|
|
21
|
-
测试警告
|
|
22
|
-
</button>
|
|
23
15
|
</div>
|
|
24
16
|
</template>
|
|
25
17
|
|
|
@@ -28,10 +20,10 @@ export default {
|
|
|
28
20
|
name: 'UserBehaviorMonitor',
|
|
29
21
|
props: {
|
|
30
22
|
// WebSocket服务器地址
|
|
31
|
-
websocketUrl: {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
},
|
|
23
|
+
// websocketUrl: {
|
|
24
|
+
// type: String,
|
|
25
|
+
// required: true
|
|
26
|
+
// },
|
|
35
27
|
// 倒计时时长(分钟)
|
|
36
28
|
timeoutMinutes: {
|
|
37
29
|
type: Number,
|
|
@@ -45,39 +37,104 @@ export default {
|
|
|
45
37
|
},
|
|
46
38
|
data() {
|
|
47
39
|
return {
|
|
48
|
-
mouseMoveThrottled:false,
|
|
49
|
-
|
|
40
|
+
mouseMoveThrottled: false,
|
|
41
|
+
socket: null,
|
|
50
42
|
countdownTimer: null,
|
|
51
43
|
warningTimer: null,
|
|
52
44
|
showWarning: false,
|
|
53
|
-
|
|
45
|
+
// warningMinutes
|
|
46
|
+
warningMessage: `您已${this.timeoutMinutes}分钟未操作,将在1分钟后自动退出`,
|
|
54
47
|
lastActivityTime: null,
|
|
55
|
-
isMonitoring: false
|
|
48
|
+
isMonitoring: false,
|
|
49
|
+
currentTimeoutMinutes: 10,
|
|
50
|
+
currentWarningMinutes: 1
|
|
56
51
|
};
|
|
57
52
|
},
|
|
58
53
|
mounted() {
|
|
59
|
-
|
|
60
|
-
this.
|
|
54
|
+
// 检查当前路由是否包含/login,如果不包含则初始化监控
|
|
55
|
+
if (!this.isLoginRoute()) {
|
|
56
|
+
this.initMonitor();
|
|
57
|
+
}
|
|
61
58
|
},
|
|
62
59
|
beforeDestroy() {
|
|
63
|
-
console.log('开始开始! beforeDestroy');
|
|
64
60
|
this.destroyMonitor();
|
|
65
61
|
},
|
|
62
|
+
watch: {
|
|
63
|
+
// 监听路由变化
|
|
64
|
+
'$route'(to, from) {
|
|
65
|
+
// 安全检查 from.href 是否存在
|
|
66
|
+
const isFromLogin = from.path.includes('/login') ||
|
|
67
|
+
(from.href && from.href.includes('/login'));
|
|
68
|
+
|
|
69
|
+
// 检查当前是否为登录路由
|
|
70
|
+
const isToLogin = this.isLoginRoute();
|
|
71
|
+
|
|
72
|
+
// 如果从登录页跳转到非登录页,且监控未启动,则初始化监控
|
|
73
|
+
if (isFromLogin && !isToLogin && !this.isMonitoring) {
|
|
74
|
+
this.initMonitor();
|
|
75
|
+
}
|
|
76
|
+
// 如果从非登录页跳转到登录页,且监控正在运行,则销毁监控
|
|
77
|
+
else if (!isFromLogin && isToLogin && this.isMonitoring) {
|
|
78
|
+
this.destroyMonitor();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
66
82
|
methods: {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
// 检查当前路由是否为登录页面
|
|
84
|
+
isLoginRoute() {
|
|
85
|
+
// 优先检查 Vue Router 路由
|
|
86
|
+
if (this.$route && this.$route.path) {
|
|
87
|
+
if (this.$route.path.includes('/login')) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 检查浏览器地址栏作为后备
|
|
93
|
+
if (typeof window !== 'undefined') {
|
|
94
|
+
return window.location.pathname.includes('/login') ||
|
|
95
|
+
window.location.href.includes('/login');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return false;
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
updateTimeoutSettings(timeoutMinutes, warningMinutes) {
|
|
102
|
+
if (timeoutMinutes !== undefined) {
|
|
103
|
+
this.currentTimeoutMinutes = timeoutMinutes;
|
|
104
|
+
localStorage.setItem('userBehavior_timeoutMinutes', timeoutMinutes.toString());
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (warningMinutes !== undefined) {
|
|
108
|
+
this.currentWarningMinutes = warningMinutes;
|
|
109
|
+
localStorage.setItem('userBehavior_warningMinutes', warningMinutes.toString());
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 更新警告消息
|
|
113
|
+
// ${this.currentWarningMinutes}
|
|
114
|
+
this.warningMessage = `您已${this.currentTimeoutMinutes}分钟未操作,将在1分钟后自动退出`;
|
|
115
|
+
|
|
116
|
+
// 重置计时器
|
|
117
|
+
this.resetTimer();
|
|
70
118
|
},
|
|
71
119
|
// 初始化监控
|
|
72
120
|
initMonitor() {
|
|
73
|
-
|
|
121
|
+
// 再次检查确保不在登录页面
|
|
122
|
+
if (this.isLoginRoute()) {
|
|
123
|
+
// 如果在登录页面,确保清理所有监控资源
|
|
124
|
+
this.destroyMonitor();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
74
128
|
if (this.isMonitoring) return;
|
|
75
129
|
|
|
76
130
|
this.isMonitoring = true;
|
|
77
131
|
this.lastActivityTime = Date.now();
|
|
78
132
|
|
|
133
|
+
// 初始化WebSocket连接
|
|
134
|
+
this.initWebSocket();
|
|
135
|
+
|
|
79
136
|
// 启动倒计时
|
|
80
|
-
this.startCountdown();
|
|
137
|
+
// this.startCountdown();
|
|
81
138
|
|
|
82
139
|
// 绑定事件监听器
|
|
83
140
|
this.bindEventListeners();
|
|
@@ -91,71 +148,183 @@ export default {
|
|
|
91
148
|
if (this.countdownTimer) clearInterval(this.countdownTimer);
|
|
92
149
|
if (this.warningTimer) clearTimeout(this.warningTimer);
|
|
93
150
|
|
|
151
|
+
// 关闭WebSocket连接
|
|
152
|
+
if (this.socket) {
|
|
153
|
+
this.socket.close();
|
|
154
|
+
this.socket = null;
|
|
155
|
+
}
|
|
156
|
+
|
|
94
157
|
// 解绑事件监听器
|
|
95
158
|
this.unbindEventListeners();
|
|
96
159
|
},
|
|
97
160
|
|
|
161
|
+
// 初始化WebSocket连接
|
|
162
|
+
initWebSocket() {
|
|
163
|
+
try {
|
|
164
|
+
// 使用传入的WebSocket URL
|
|
165
|
+
const websocketUrl = `wss://${location.host}/xy-api/auth-server/ws/user-activity`;
|
|
166
|
+
|
|
167
|
+
// 获取token(假设存储在localStorage中)
|
|
168
|
+
let token = '';
|
|
169
|
+
try {
|
|
170
|
+
const apiHeader = localStorage.getItem('api_header');
|
|
171
|
+
if (apiHeader) {
|
|
172
|
+
token = JSON.parse(apiHeader).Authorization || '';
|
|
173
|
+
}
|
|
174
|
+
} catch (e) {
|
|
175
|
+
token = localStorage.getItem('token') || '';
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 创建WebSocket连接
|
|
179
|
+
this.socket = new WebSocket(`${websocketUrl}?token=${encodeURIComponent(token)}`);
|
|
180
|
+
|
|
181
|
+
// 设置连接成功回调
|
|
182
|
+
this.socket.onopen = () => {
|
|
183
|
+
console.log('WebSocket连接已建立');
|
|
184
|
+
this.sendUserBehavior();
|
|
185
|
+
this.$emit('websocket-open');
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// 设置接收消息回调
|
|
189
|
+
this.socket.onmessage = (event) => {
|
|
190
|
+
try {
|
|
191
|
+
const data = JSON.parse(event.data);
|
|
192
|
+
console.log('收到用户活动状态消息:', data);
|
|
193
|
+
this.handleActivityStatus(data);
|
|
194
|
+
this.$emit('websocket-message', data);
|
|
195
|
+
} catch (e) {
|
|
196
|
+
console.error('解析WebSocket消息失败:', e);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// 设置连接关闭回调
|
|
201
|
+
this.socket.onclose = (event) => {
|
|
202
|
+
console.log('WebSocket连接已断开:', event.reason);
|
|
203
|
+
this.$emit('websocket-close');
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// 设置连接错误回调
|
|
207
|
+
this.socket.onerror = (error) => {
|
|
208
|
+
console.error('WebSocket错误:', error);
|
|
209
|
+
this.$emit('websocket-error', error);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
} catch (error) {
|
|
213
|
+
console.error('WebSocket初始化失败:', error);
|
|
214
|
+
this.$emit('websocket-error', error);
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
// 处理活动状态信息
|
|
219
|
+
handleActivityStatus(data) {
|
|
220
|
+
if (data.type === 'ACTIVITY_STATUS' && data.data) {
|
|
221
|
+
const activityData = data.data;
|
|
222
|
+
|
|
223
|
+
// 更新超时和警告时间配置
|
|
224
|
+
this.currentTimeoutMinutes = activityData.timeoutMinutes || 10;
|
|
225
|
+
this.currentWarningMinutes = activityData.reminderMinutes || 1;
|
|
226
|
+
|
|
227
|
+
// 更新警告消息
|
|
228
|
+
this.warningMessage = `您已${this.currentTimeoutMinutes}分钟未操作,将在${this.currentWarningMinutes}分钟后自动退出`;
|
|
229
|
+
if(activityData.needReminder){
|
|
230
|
+
this.showWarningWarning(activityData.remainingMillis);
|
|
231
|
+
}
|
|
232
|
+
// remainingMillis
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
// 检查是否仍然活跃
|
|
236
|
+
//if (!activityData.isActive) {
|
|
237
|
+
//this.handleInactiveStatus();
|
|
238
|
+
//}
|
|
239
|
+
}
|
|
240
|
+
// 检查是否需要显示提醒
|
|
241
|
+
// let dataReminder=data.data;
|
|
242
|
+
// if (dataReminder&&dataReminder.needReminder) {
|
|
243
|
+
// this.showWarningWarning(dataReminder.remainingSeconds);
|
|
244
|
+
// }
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
// 处理非活跃状态
|
|
248
|
+
handleInactiveStatus() {
|
|
249
|
+
// 清空缓存
|
|
250
|
+
localStorage.clear();
|
|
251
|
+
sessionStorage.clear();
|
|
252
|
+
|
|
253
|
+
// 跳转到登录页
|
|
254
|
+
//this.$router.push('/login');
|
|
255
|
+
|
|
256
|
+
// 或者使用window.location
|
|
257
|
+
window.location.href = '/login';
|
|
258
|
+
|
|
259
|
+
// 触发登出事件
|
|
260
|
+
this.$emit('logout');
|
|
261
|
+
},
|
|
262
|
+
|
|
98
263
|
// 发送用户行为数据到后端
|
|
99
264
|
sendUserBehavior(data) {
|
|
100
|
-
|
|
101
|
-
|
|
265
|
+
console.log('用户行为监测:')
|
|
266
|
+
if (this.warningTimer) clearTimeout(this.warningTimer);
|
|
267
|
+
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
268
|
+
const message = {
|
|
269
|
+
"type": "HEARTBEAT",
|
|
270
|
+
"message": "心跳",
|
|
271
|
+
};
|
|
272
|
+
console.log('用户行为监测:', JSON.stringify(message));
|
|
273
|
+
this.socket.send(JSON.stringify(message));
|
|
274
|
+
}
|
|
102
275
|
},
|
|
103
276
|
|
|
104
277
|
// 绑定事件监听器
|
|
105
278
|
bindEventListeners() {
|
|
106
|
-
console.log('Binding event listeners');
|
|
107
|
-
// 使用箭头函数或bind来保持this上下文
|
|
108
279
|
// 鼠标事件
|
|
109
|
-
document.addEventListener('click', this.handleUserActivity
|
|
110
|
-
document.addEventListener('dblclick', this.handleUserActivity
|
|
111
|
-
document.addEventListener('mousedown', this.handleUserActivity
|
|
112
|
-
document.addEventListener('mouseup', this.handleUserActivity
|
|
113
|
-
document.addEventListener('mousemove', this.handleMouseMove
|
|
114
|
-
document.addEventListener('mouseover', this.handleUserActivity
|
|
115
|
-
document.addEventListener('mouseout', this.handleUserActivity
|
|
280
|
+
document.addEventListener('click', this.handleUserActivity, true);
|
|
281
|
+
document.addEventListener('dblclick', this.handleUserActivity, true);
|
|
282
|
+
document.addEventListener('mousedown', this.handleUserActivity, true);
|
|
283
|
+
document.addEventListener('mouseup', this.handleUserActivity, true);
|
|
284
|
+
document.addEventListener('mousemove', this.handleMouseMove, true);
|
|
285
|
+
document.addEventListener('mouseover', this.handleUserActivity, true);
|
|
286
|
+
document.addEventListener('mouseout', this.handleUserActivity, true);
|
|
116
287
|
|
|
117
288
|
// 键盘事件
|
|
118
|
-
document.addEventListener('keydown', this.handleUserActivity
|
|
119
|
-
document.addEventListener('keyup', this.handleUserActivity
|
|
289
|
+
document.addEventListener('keydown', this.handleUserActivity, true);
|
|
290
|
+
document.addEventListener('keyup', this.handleUserActivity, true);
|
|
120
291
|
|
|
121
292
|
// 表单事件
|
|
122
|
-
document.addEventListener('input', this.handleUserActivity
|
|
123
|
-
document.addEventListener('change', this.handleUserActivity
|
|
124
|
-
document.addEventListener('focus', this.handleUserActivity
|
|
125
|
-
document.addEventListener('blur', this.handleUserActivity
|
|
293
|
+
document.addEventListener('input', this.handleUserActivity, true);
|
|
294
|
+
document.addEventListener('change', this.handleUserActivity, true);
|
|
295
|
+
document.addEventListener('focus', this.handleUserActivity, true);
|
|
296
|
+
document.addEventListener('blur', this.handleUserActivity, true);
|
|
126
297
|
|
|
127
298
|
// 滚动事件(防抖处理)
|
|
128
|
-
document.addEventListener('scroll', this.debounce(this.handleUserActivity, 300)
|
|
299
|
+
document.addEventListener('scroll', this.debounce(this.handleUserActivity, 300), true);
|
|
129
300
|
|
|
130
301
|
// 窗口事件
|
|
131
|
-
window.addEventListener('resize', this.handleUserActivity
|
|
132
|
-
window.addEventListener('beforeunload', this.handleBeforeUnload
|
|
302
|
+
window.addEventListener('resize', this.handleUserActivity, true);
|
|
303
|
+
window.addEventListener('beforeunload', this.handleBeforeUnload);
|
|
133
304
|
},
|
|
134
305
|
|
|
135
306
|
// 解绑事件监听器
|
|
136
307
|
unbindEventListeners() {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
document.removeEventListener('
|
|
140
|
-
document.removeEventListener('
|
|
141
|
-
document.removeEventListener('
|
|
142
|
-
document.removeEventListener('
|
|
143
|
-
document.removeEventListener('
|
|
144
|
-
|
|
145
|
-
document.removeEventListener('
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
document.removeEventListener('
|
|
149
|
-
|
|
150
|
-
document.removeEventListener('
|
|
151
|
-
document.removeEventListener('
|
|
152
|
-
|
|
153
|
-
document.removeEventListener('
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
window.removeEventListener('resize', this.handleUserActivity.bind(this), true);
|
|
158
|
-
window.removeEventListener('beforeunload', this.handleBeforeUnload.bind(this));
|
|
308
|
+
document.removeEventListener('click', this.handleUserActivity, true);
|
|
309
|
+
document.removeEventListener('dblclick', this.handleUserActivity, true);
|
|
310
|
+
document.removeEventListener('mousedown', this.handleUserActivity, true);
|
|
311
|
+
document.removeEventListener('mouseup', this.handleUserActivity, true);
|
|
312
|
+
document.removeEventListener('mousemove', this.handleMouseMove, true);
|
|
313
|
+
document.removeEventListener('mouseover', this.handleUserActivity, true);
|
|
314
|
+
document.removeEventListener('mouseout', this.handleUserActivity, true);
|
|
315
|
+
|
|
316
|
+
document.removeEventListener('keydown', this.handleUserActivity, true);
|
|
317
|
+
document.removeEventListener('keyup', this.handleUserActivity, true);
|
|
318
|
+
|
|
319
|
+
document.removeEventListener('input', this.handleUserActivity, true);
|
|
320
|
+
document.removeEventListener('change', this.handleUserActivity, true);
|
|
321
|
+
document.removeEventListener('focus', this.handleUserActivity, true);
|
|
322
|
+
document.removeEventListener('blur', this.handleUserActivity, true);
|
|
323
|
+
|
|
324
|
+
document.removeEventListener('scroll', this.debounce(this.handleUserActivity, 300), true);
|
|
325
|
+
|
|
326
|
+
window.removeEventListener('resize', this.handleUserActivity, true);
|
|
327
|
+
window.removeEventListener('beforeunload', this.handleBeforeUnload);
|
|
159
328
|
},
|
|
160
329
|
|
|
161
330
|
// 处理用户活动
|
|
@@ -186,7 +355,7 @@ export default {
|
|
|
186
355
|
|
|
187
356
|
this.sendUserBehavior(behaviorData);
|
|
188
357
|
},
|
|
189
|
-
|
|
358
|
+
handleMouseMove(event) {
|
|
190
359
|
if (!this.mouseMoveThrottled) {
|
|
191
360
|
this.handleUserActivity(event);
|
|
192
361
|
this.mouseMoveThrottled = true;
|
|
@@ -196,20 +365,6 @@ export default {
|
|
|
196
365
|
}
|
|
197
366
|
},
|
|
198
367
|
|
|
199
|
-
// 处理鼠标移动(降低频率)
|
|
200
|
-
// handleMouseMove: function() {
|
|
201
|
-
// let isThrottled = false;
|
|
202
|
-
// return (event) => {
|
|
203
|
-
// if (!isThrottled) {
|
|
204
|
-
// this.handleUserActivity(event);
|
|
205
|
-
// isThrottled = true;
|
|
206
|
-
// setTimeout(() => {
|
|
207
|
-
// isThrottled = false;
|
|
208
|
-
// }, 500);
|
|
209
|
-
// }
|
|
210
|
-
// };
|
|
211
|
-
// }(),
|
|
212
|
-
|
|
213
368
|
// 判断是否为自动触发事件
|
|
214
369
|
isAutomaticEvent(event) {
|
|
215
370
|
// 自动刷新等非用户主动触发的事件
|
|
@@ -234,7 +389,6 @@ export default {
|
|
|
234
389
|
|
|
235
390
|
// 重置计时器
|
|
236
391
|
resetTimer() {
|
|
237
|
-
console.log('Resetting timer');
|
|
238
392
|
this.lastActivityTime = Date.now();
|
|
239
393
|
this.showWarning = false;
|
|
240
394
|
|
|
@@ -245,52 +399,48 @@ export default {
|
|
|
245
399
|
}
|
|
246
400
|
|
|
247
401
|
// 重新启动倒计时
|
|
248
|
-
this.startCountdown();
|
|
402
|
+
// this.startCountdown();
|
|
249
403
|
|
|
250
404
|
this.$emit('user-active');
|
|
251
405
|
},
|
|
252
406
|
|
|
253
407
|
// 启动倒计时
|
|
254
408
|
startCountdown() {
|
|
255
|
-
console.log('Starting countdown');
|
|
256
409
|
// 清除现有定时器
|
|
257
410
|
if (this.countdownTimer) clearInterval(this.countdownTimer);
|
|
258
411
|
|
|
259
412
|
// 设置新的倒计时
|
|
260
413
|
this.countdownTimer = setInterval(() => {
|
|
261
414
|
const now = Date.now();
|
|
262
|
-
const elapsedMinutes = (now - this.lastActivityTime) / (1000 *
|
|
263
|
-
console.log('Elapsed minutes:', elapsedMinutes);
|
|
415
|
+
const elapsedMinutes = (now - this.lastActivityTime) / (1000 * 50);
|
|
264
416
|
|
|
265
417
|
// 检查是否需要显示警告
|
|
266
|
-
if (elapsedMinutes >= (this.
|
|
267
|
-
console.log('Showing warning');
|
|
418
|
+
if (elapsedMinutes >= (this.currentTimeoutMinutes - this.currentWarningMinutes) && !this.warningTimer) {
|
|
268
419
|
this.showWarningWarning();
|
|
269
420
|
}
|
|
270
421
|
|
|
271
422
|
// 检查是否超时
|
|
272
|
-
if (elapsedMinutes >= this.
|
|
273
|
-
console.log('Handling timeout');
|
|
423
|
+
if (elapsedMinutes >= this.currentTimeoutMinutes) {
|
|
274
424
|
this.handleTimeout();
|
|
275
425
|
}
|
|
276
426
|
}, 1000);
|
|
277
427
|
},
|
|
278
428
|
|
|
279
429
|
// 显示超时警告
|
|
280
|
-
showWarningWarning() {
|
|
430
|
+
showWarningWarning(timeoutMinutes) {
|
|
431
|
+
let time=timeoutMinutes||50;
|
|
281
432
|
console.log('Setting showWarning to true');
|
|
282
433
|
this.showWarning = true;
|
|
283
434
|
this.$emit('timeout-warning');
|
|
284
|
-
|
|
435
|
+
if (this.warningTimer) clearTimeout(this.warningTimer);
|
|
285
436
|
// 设置超时处理
|
|
286
437
|
this.warningTimer = setTimeout(() => {
|
|
287
438
|
this.handleTimeout();
|
|
288
|
-
},
|
|
439
|
+
}, 1 * time * 1000);
|
|
289
440
|
},
|
|
290
441
|
|
|
291
442
|
// 处理超时
|
|
292
443
|
handleTimeout() {
|
|
293
|
-
console.log('Handling timeout');
|
|
294
444
|
this.showWarning = false;
|
|
295
445
|
this.$emit('timeout');
|
|
296
446
|
|
|
@@ -300,9 +450,24 @@ export default {
|
|
|
300
450
|
|
|
301
451
|
// 登出操作
|
|
302
452
|
logout() {
|
|
303
|
-
|
|
304
|
-
|
|
453
|
+
localStorage.clear();
|
|
454
|
+
sessionStorage.clear();
|
|
455
|
+
location.reload();
|
|
456
|
+
// 跳转到登录页
|
|
457
|
+
//this.$router.push('/login');
|
|
305
458
|
|
|
459
|
+
// 或者使用window.location
|
|
460
|
+
// window.location.href = '/login';
|
|
461
|
+
// 发送登出消息到后端
|
|
462
|
+
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
463
|
+
const message = {
|
|
464
|
+
type: 'logout',
|
|
465
|
+
timestamp: Date.now()
|
|
466
|
+
};
|
|
467
|
+
this.socket.send(JSON.stringify(message));
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// 触发登出事件
|
|
306
471
|
this.$emit('logout');
|
|
307
472
|
|
|
308
473
|
// 清除定时器
|
|
@@ -312,32 +477,45 @@ export default {
|
|
|
312
477
|
|
|
313
478
|
// 处理页面卸载前的操作
|
|
314
479
|
handleBeforeUnload(event) {
|
|
315
|
-
//
|
|
316
|
-
|
|
480
|
+
// 发送页面关闭消息
|
|
481
|
+
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
482
|
+
const message = {
|
|
483
|
+
type: 'page_unload',
|
|
484
|
+
timestamp: Date.now()
|
|
485
|
+
};
|
|
486
|
+
this.socket.send(JSON.stringify(message));
|
|
487
|
+
}
|
|
317
488
|
},
|
|
318
489
|
|
|
319
490
|
// 手动重置监控
|
|
320
491
|
reset() {
|
|
492
|
+
// 检查当前路由,如果在登录页面则销毁监控
|
|
493
|
+
if (this.isLoginRoute()) {
|
|
494
|
+
this.destroyMonitor();
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
|
|
321
498
|
this.resetTimer();
|
|
499
|
+
},
|
|
500
|
+
|
|
501
|
+
// 重新连接WebSocket
|
|
502
|
+
reconnect() {
|
|
503
|
+
// 检查当前路由,如果在登录页面则销毁监控
|
|
504
|
+
if (this.isLoginRoute()) {
|
|
505
|
+
this.destroyMonitor();
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (this.socket) {
|
|
510
|
+
this.socket.close();
|
|
511
|
+
}
|
|
512
|
+
this.initWebSocket();
|
|
322
513
|
}
|
|
323
514
|
}
|
|
324
515
|
};
|
|
325
516
|
</script>
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
display: none;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/* 使用深度选择器确保样式正确应用 */
|
|
333
|
-
.behavior-warning-dialog ::v-deep .el-dialog__body {
|
|
334
|
-
text-align: center;
|
|
335
|
-
font-size: 16px;
|
|
336
|
-
padding: 30px 20px;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/* 确保弹框在最上层 */
|
|
340
|
-
.behavior-warning-dialog {
|
|
341
|
-
z-index: 9999 !important;
|
|
517
|
+
<style>
|
|
518
|
+
.behavior-warning-dialog.el-dialog.el-dialog--center{
|
|
519
|
+
text-align: left;
|
|
342
520
|
}
|
|
343
521
|
</style>
|