modernx-gui 1.1.5 → 1.2.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/dist/index.html +511 -96
- package/package.json +1 -1
package/dist/index.html
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>ModernX GUI
|
|
6
|
+
<title>ModernX GUI - 实时状态监控</title>
|
|
7
|
+
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
|
7
8
|
<style>
|
|
8
9
|
* {
|
|
9
10
|
margin: 0;
|
|
@@ -12,99 +13,220 @@
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
body {
|
|
15
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
16
|
-
background: #
|
|
16
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
|
|
17
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
17
18
|
color: #333;
|
|
19
|
+
overflow: hidden;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
.header {
|
|
21
|
-
background:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
background: rgba(255, 255, 255, 0.95);
|
|
24
|
+
backdrop-filter: blur(10px);
|
|
25
|
+
padding: 1rem 2rem;
|
|
26
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
|
27
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
28
|
+
display: flex;
|
|
29
|
+
justify-content: space-between;
|
|
30
|
+
align-items: center;
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
.header h1 {
|
|
28
34
|
font-size: 1.5rem;
|
|
29
|
-
|
|
35
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
36
|
+
-webkit-background-clip: text;
|
|
37
|
+
-webkit-text-fill-color: transparent;
|
|
38
|
+
font-weight: 700;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.status-badge {
|
|
42
|
+
padding: 0.5rem 1rem;
|
|
43
|
+
border-radius: 20px;
|
|
44
|
+
font-size: 0.8rem;
|
|
45
|
+
font-weight: 600;
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
gap: 0.5rem;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.status-badge.connected {
|
|
52
|
+
background: linear-gradient(135deg, #4CAF50, #45a049);
|
|
53
|
+
color: white;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.status-badge.disconnected {
|
|
57
|
+
background: linear-gradient(135deg, #f44336, #d32f2f);
|
|
58
|
+
color: white;
|
|
30
59
|
}
|
|
31
60
|
|
|
32
|
-
.container {
|
|
61
|
+
.main-container {
|
|
33
62
|
display: flex;
|
|
34
|
-
height: calc(100vh -
|
|
63
|
+
height: calc(100vh - 70px);
|
|
35
64
|
}
|
|
36
65
|
|
|
37
66
|
.sidebar {
|
|
38
|
-
width:
|
|
39
|
-
background:
|
|
40
|
-
|
|
67
|
+
width: 280px;
|
|
68
|
+
background: rgba(255, 255, 255, 0.95);
|
|
69
|
+
backdrop-filter: blur(10px);
|
|
70
|
+
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
|
71
|
+
overflow-y: auto;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.sidebar-section {
|
|
75
|
+
padding: 1.5rem;
|
|
76
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.sidebar-section h3 {
|
|
80
|
+
font-size: 0.9rem;
|
|
81
|
+
text-transform: uppercase;
|
|
82
|
+
color: #666;
|
|
83
|
+
margin-bottom: 1rem;
|
|
84
|
+
font-weight: 600;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.project-info {
|
|
88
|
+
background: rgba(102, 126, 234, 0.1);
|
|
89
|
+
border-radius: 12px;
|
|
41
90
|
padding: 1rem;
|
|
91
|
+
margin-bottom: 1rem;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.project-info-item {
|
|
95
|
+
display: flex;
|
|
96
|
+
justify-content: space-between;
|
|
97
|
+
margin-bottom: 0.5rem;
|
|
98
|
+
font-size: 0.9rem;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.project-info-item:last-child {
|
|
102
|
+
margin-bottom: 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.model-item {
|
|
106
|
+
background: white;
|
|
107
|
+
border-radius: 8px;
|
|
108
|
+
padding: 1rem;
|
|
109
|
+
margin-bottom: 0.8rem;
|
|
110
|
+
cursor: pointer;
|
|
111
|
+
transition: all 0.3s ease;
|
|
112
|
+
border: 2px solid transparent;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.model-item:hover {
|
|
116
|
+
transform: translateY(-2px);
|
|
117
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
118
|
+
border-color: #667eea;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.model-item.active {
|
|
122
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
123
|
+
color: white;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.model-name {
|
|
127
|
+
font-weight: 600;
|
|
128
|
+
margin-bottom: 0.5rem;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.model-state-count {
|
|
132
|
+
font-size: 0.8rem;
|
|
133
|
+
opacity: 0.8;
|
|
42
134
|
}
|
|
43
135
|
|
|
44
|
-
.
|
|
136
|
+
.content-area {
|
|
45
137
|
flex: 1;
|
|
46
138
|
display: flex;
|
|
47
139
|
flex-direction: column;
|
|
140
|
+
background: rgba(255, 255, 255, 0.95);
|
|
141
|
+
backdrop-filter: blur(10px);
|
|
48
142
|
}
|
|
49
143
|
|
|
50
144
|
.tabs {
|
|
51
|
-
background: #fff;
|
|
52
|
-
border-bottom: 1px solid #e0e0e0;
|
|
53
145
|
display: flex;
|
|
146
|
+
background: rgba(255, 255, 255, 0.8);
|
|
147
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
|
54
148
|
}
|
|
55
149
|
|
|
56
150
|
.tab {
|
|
57
151
|
padding: 1rem 2rem;
|
|
58
152
|
cursor: pointer;
|
|
59
|
-
border-bottom:
|
|
153
|
+
border-bottom: 3px solid transparent;
|
|
154
|
+
transition: all 0.3s ease;
|
|
155
|
+
font-weight: 500;
|
|
156
|
+
position: relative;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.tab:hover {
|
|
160
|
+
background: rgba(102, 126, 234, 0.1);
|
|
60
161
|
}
|
|
61
162
|
|
|
62
163
|
.tab.active {
|
|
63
|
-
border-bottom-color: #
|
|
64
|
-
color: #
|
|
164
|
+
border-bottom-color: #667eea;
|
|
165
|
+
color: #667eea;
|
|
65
166
|
}
|
|
66
167
|
|
|
67
|
-
.content {
|
|
168
|
+
.tab-content {
|
|
68
169
|
flex: 1;
|
|
69
|
-
padding:
|
|
170
|
+
padding: 2rem;
|
|
70
171
|
overflow-y: auto;
|
|
71
172
|
}
|
|
72
173
|
|
|
73
174
|
.state-view {
|
|
74
|
-
background:
|
|
75
|
-
border-radius:
|
|
76
|
-
padding:
|
|
77
|
-
margin-bottom:
|
|
78
|
-
box-shadow: 0 2px
|
|
175
|
+
background: white;
|
|
176
|
+
border-radius: 12px;
|
|
177
|
+
padding: 1.5rem;
|
|
178
|
+
margin-bottom: 1.5rem;
|
|
179
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
79
180
|
}
|
|
80
181
|
|
|
81
182
|
.state-view h3 {
|
|
82
|
-
margin-bottom:
|
|
183
|
+
margin-bottom: 1rem;
|
|
83
184
|
color: #333;
|
|
185
|
+
font-size: 1.1rem;
|
|
186
|
+
display: flex;
|
|
187
|
+
align-items: center;
|
|
188
|
+
gap: 0.5rem;
|
|
84
189
|
}
|
|
85
190
|
|
|
86
191
|
.state-json {
|
|
87
|
-
background: #
|
|
192
|
+
background: #f8f9fa;
|
|
193
|
+
border: 1px solid #e9ecef;
|
|
194
|
+
border-radius: 8px;
|
|
88
195
|
padding: 1rem;
|
|
89
|
-
|
|
90
|
-
font-family: 'Monaco', 'Menlo', monospace;
|
|
196
|
+
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
|
|
91
197
|
font-size: 0.9rem;
|
|
92
198
|
white-space: pre-wrap;
|
|
93
199
|
word-break: break-all;
|
|
200
|
+
max-height: 400px;
|
|
201
|
+
overflow-y: auto;
|
|
94
202
|
}
|
|
95
203
|
|
|
96
204
|
.action-item {
|
|
97
|
-
background:
|
|
98
|
-
border-radius:
|
|
99
|
-
padding: 1rem;
|
|
100
|
-
margin-bottom:
|
|
205
|
+
background: white;
|
|
206
|
+
border-radius: 12px;
|
|
207
|
+
padding: 1rem 1.5rem;
|
|
208
|
+
margin-bottom: 1rem;
|
|
101
209
|
border-left: 4px solid #4CAF50;
|
|
102
|
-
box-shadow: 0 2px
|
|
210
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
211
|
+
transition: all 0.3s ease;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.action-item:hover {
|
|
215
|
+
transform: translateX(4px);
|
|
216
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.action-header {
|
|
220
|
+
display: flex;
|
|
221
|
+
justify-content: space-between;
|
|
222
|
+
align-items: center;
|
|
223
|
+
margin-bottom: 0.5rem;
|
|
103
224
|
}
|
|
104
225
|
|
|
105
226
|
.action-type {
|
|
106
|
-
font-weight:
|
|
107
|
-
color: #
|
|
227
|
+
font-weight: 600;
|
|
228
|
+
color: #667eea;
|
|
229
|
+
font-size: 1rem;
|
|
108
230
|
}
|
|
109
231
|
|
|
110
232
|
.action-time {
|
|
@@ -112,63 +234,231 @@
|
|
|
112
234
|
font-size: 0.8rem;
|
|
113
235
|
}
|
|
114
236
|
|
|
115
|
-
.
|
|
237
|
+
.action-payload {
|
|
238
|
+
background: #f8f9fa;
|
|
239
|
+
border-radius: 6px;
|
|
240
|
+
padding: 0.5rem;
|
|
241
|
+
font-family: monospace;
|
|
242
|
+
font-size: 0.9rem;
|
|
243
|
+
color: #495057;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.model-detail {
|
|
247
|
+
background: white;
|
|
248
|
+
border-radius: 12px;
|
|
249
|
+
padding: 1.5rem;
|
|
250
|
+
margin-bottom: 1.5rem;
|
|
251
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.model-detail-header {
|
|
255
|
+
display: flex;
|
|
256
|
+
justify-content: space-between;
|
|
257
|
+
align-items: center;
|
|
258
|
+
margin-bottom: 1rem;
|
|
259
|
+
padding-bottom: 1rem;
|
|
260
|
+
border-bottom: 2px solid #f0f0f0;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.model-detail-title {
|
|
264
|
+
font-size: 1.2rem;
|
|
265
|
+
font-weight: 600;
|
|
266
|
+
color: #333;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.model-detail-actions {
|
|
270
|
+
display: flex;
|
|
271
|
+
gap: 0.5rem;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.btn {
|
|
116
275
|
padding: 0.5rem 1rem;
|
|
117
|
-
border
|
|
276
|
+
border: none;
|
|
277
|
+
border-radius: 6px;
|
|
278
|
+
cursor: pointer;
|
|
118
279
|
font-size: 0.8rem;
|
|
119
|
-
|
|
280
|
+
transition: all 0.3s ease;
|
|
281
|
+
font-weight: 500;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.btn-primary {
|
|
285
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
286
|
+
color: white;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.btn-secondary {
|
|
290
|
+
background: #f8f9fa;
|
|
291
|
+
color: #495057;
|
|
292
|
+
border: 1px solid #dee2e6;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.btn:hover {
|
|
296
|
+
transform: translateY(-2px);
|
|
297
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|
120
298
|
}
|
|
121
299
|
|
|
122
|
-
.
|
|
123
|
-
|
|
124
|
-
|
|
300
|
+
.stats-grid {
|
|
301
|
+
display: grid;
|
|
302
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
303
|
+
gap: 1rem;
|
|
304
|
+
margin-bottom: 2rem;
|
|
125
305
|
}
|
|
126
306
|
|
|
127
|
-
.
|
|
128
|
-
background:
|
|
129
|
-
|
|
307
|
+
.stat-card {
|
|
308
|
+
background: white;
|
|
309
|
+
border-radius: 12px;
|
|
310
|
+
padding: 1.5rem;
|
|
311
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
312
|
+
text-align: center;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.stat-value {
|
|
316
|
+
font-size: 2rem;
|
|
317
|
+
font-weight: 700;
|
|
318
|
+
color: #667eea;
|
|
319
|
+
margin-bottom: 0.5rem;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.stat-label {
|
|
323
|
+
color: #666;
|
|
324
|
+
font-size: 0.9rem;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.loading {
|
|
328
|
+
display: flex;
|
|
329
|
+
justify-content: center;
|
|
330
|
+
align-items: center;
|
|
331
|
+
height: 200px;
|
|
332
|
+
color: #666;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.spinner {
|
|
336
|
+
border: 3px solid #f3f3f3;
|
|
337
|
+
border-top: 3px solid #667eea;
|
|
338
|
+
border-radius: 50%;
|
|
339
|
+
width: 40px;
|
|
340
|
+
height: 40px;
|
|
341
|
+
animation: spin 1s linear infinite;
|
|
342
|
+
margin-right: 1rem;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
@keyframes spin {
|
|
346
|
+
0% { transform: rotate(0deg); }
|
|
347
|
+
100% { transform: rotate(360deg); }
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.empty-state {
|
|
351
|
+
text-align: center;
|
|
352
|
+
padding: 3rem;
|
|
353
|
+
color: #666;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.empty-state i {
|
|
357
|
+
font-size: 3rem;
|
|
358
|
+
margin-bottom: 1rem;
|
|
359
|
+
opacity: 0.5;
|
|
130
360
|
}
|
|
131
361
|
</style>
|
|
132
362
|
</head>
|
|
133
363
|
<body>
|
|
134
|
-
<
|
|
135
|
-
<h1
|
|
136
|
-
<div class="status" id="connection-status"
|
|
137
|
-
|
|
364
|
+
<header class="header">
|
|
365
|
+
<h1><i class="fas fa-rocket"></i> ModernX GUI</h1>
|
|
366
|
+
<div class="status-badge" id="connection-status">
|
|
367
|
+
<i class="fas fa-circle"></i>
|
|
368
|
+
<span>连接中...</span>
|
|
369
|
+
</div>
|
|
370
|
+
</header>
|
|
138
371
|
|
|
139
|
-
<div class="container">
|
|
140
|
-
<
|
|
141
|
-
<
|
|
142
|
-
|
|
372
|
+
<div class="main-container">
|
|
373
|
+
<aside class="sidebar">
|
|
374
|
+
<div class="sidebar-section">
|
|
375
|
+
<h3><i class="fas fa-info-circle"></i> 项目信息</h3>
|
|
376
|
+
<div class="project-info" id="project-info">
|
|
377
|
+
<div class="loading">
|
|
378
|
+
<div class="spinner"></div>
|
|
379
|
+
加载中...
|
|
380
|
+
</div>
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
143
383
|
|
|
144
|
-
<
|
|
145
|
-
|
|
146
|
-
|
|
384
|
+
<div class="sidebar-section">
|
|
385
|
+
<h3><i class="fas fa-cubes"></i> 模型列表</h3>
|
|
386
|
+
<div id="models-list">
|
|
387
|
+
<div class="loading">
|
|
388
|
+
<div class="spinner"></div>
|
|
389
|
+
加载中...
|
|
390
|
+
</div>
|
|
391
|
+
</div>
|
|
392
|
+
</div>
|
|
393
|
+
</aside>
|
|
147
394
|
|
|
148
|
-
<
|
|
395
|
+
<main class="content-area">
|
|
149
396
|
<div class="tabs">
|
|
150
|
-
<div class="tab active" data-tab="
|
|
151
|
-
|
|
152
|
-
|
|
397
|
+
<div class="tab active" data-tab="dashboard">
|
|
398
|
+
<i class="fas fa-tachometer-alt"></i> 仪表板
|
|
399
|
+
</div>
|
|
400
|
+
<div class="tab" data-tab="state">
|
|
401
|
+
<i class="fas fa-database"></i> 状态
|
|
402
|
+
</div>
|
|
403
|
+
<div class="tab" data-tab="actions">
|
|
404
|
+
<i class="fas fa-history"></i> 动作历史
|
|
405
|
+
</div>
|
|
406
|
+
<div class="tab" data-tab="models">
|
|
407
|
+
<i class="fas fa-cube"></i> 模型详情
|
|
408
|
+
</div>
|
|
153
409
|
</div>
|
|
154
410
|
|
|
155
|
-
<div class="content">
|
|
156
|
-
<div
|
|
157
|
-
<div class="
|
|
158
|
-
<
|
|
159
|
-
<div class="
|
|
411
|
+
<div class="tab-content" id="dashboard-content">
|
|
412
|
+
<div class="stats-grid">
|
|
413
|
+
<div class="stat-card">
|
|
414
|
+
<div class="stat-value" id="total-actions">0</div>
|
|
415
|
+
<div class="stat-label">总动作数</div>
|
|
416
|
+
</div>
|
|
417
|
+
<div class="stat-card">
|
|
418
|
+
<div class="stat-value" id="total-models">0</div>
|
|
419
|
+
<div class="stat-label">模型数量</div>
|
|
420
|
+
</div>
|
|
421
|
+
<div class="stat-card">
|
|
422
|
+
<div class="stat-value" id="connection-uptime">0s</div>
|
|
423
|
+
<div class="stat-label">连接时长</div>
|
|
424
|
+
</div>
|
|
425
|
+
<div class="stat-card">
|
|
426
|
+
<div class="stat-value" id="state-changes">0</div>
|
|
427
|
+
<div class="stat-label">状态变化</div>
|
|
160
428
|
</div>
|
|
161
429
|
</div>
|
|
162
430
|
|
|
163
|
-
<div
|
|
164
|
-
<
|
|
431
|
+
<div class="state-view">
|
|
432
|
+
<h3><i class="fas fa-database"></i> 当前状态概览</h3>
|
|
433
|
+
<div class="state-json" id="dashboard-state">等待数据...</div>
|
|
165
434
|
</div>
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
435
|
+
</div>
|
|
436
|
+
|
|
437
|
+
<div class="tab-content" id="state-content" style="display: none;">
|
|
438
|
+
<div class="state-view">
|
|
439
|
+
<h3><i class="fas fa-database"></i> 完整状态树</h3>
|
|
440
|
+
<div class="state-json" id="current-state">等待数据...</div>
|
|
169
441
|
</div>
|
|
170
442
|
</div>
|
|
171
|
-
|
|
443
|
+
|
|
444
|
+
<div class="tab-content" id="actions-content" style="display: none;">
|
|
445
|
+
<div id="actions-list">
|
|
446
|
+
<div class="empty-state">
|
|
447
|
+
<i class="fas fa-history"></i>
|
|
448
|
+
<div>暂无动作记录</div>
|
|
449
|
+
</div>
|
|
450
|
+
</div>
|
|
451
|
+
</div>
|
|
452
|
+
|
|
453
|
+
<div class="tab-content" id="models-content" style="display: none;">
|
|
454
|
+
<div id="models-detail">
|
|
455
|
+
<div class="empty-state">
|
|
456
|
+
<i class="fas fa-cube"></i>
|
|
457
|
+
<div>暂无模型数据</div>
|
|
458
|
+
</div>
|
|
459
|
+
</div>
|
|
460
|
+
</div>
|
|
461
|
+
</main>
|
|
172
462
|
</div>
|
|
173
463
|
|
|
174
464
|
<script>
|
|
@@ -179,6 +469,11 @@
|
|
|
179
469
|
this.currentState = {};
|
|
180
470
|
this.actions = [];
|
|
181
471
|
this.models = [];
|
|
472
|
+
this.stats = {
|
|
473
|
+
totalActions: 0,
|
|
474
|
+
stateChanges: 0,
|
|
475
|
+
connectionStartTime: Date.now()
|
|
476
|
+
};
|
|
182
477
|
|
|
183
478
|
this.init();
|
|
184
479
|
}
|
|
@@ -187,6 +482,7 @@
|
|
|
187
482
|
this.fetchProjectInfo();
|
|
188
483
|
this.setupWebSocket();
|
|
189
484
|
this.setupTabs();
|
|
485
|
+
this.startStatsUpdater();
|
|
190
486
|
}
|
|
191
487
|
|
|
192
488
|
async fetchProjectInfo() {
|
|
@@ -203,12 +499,26 @@
|
|
|
203
499
|
const projectInfoEl = document.getElementById('project-info');
|
|
204
500
|
if (this.projectInfo && this.projectInfo.name) {
|
|
205
501
|
projectInfoEl.innerHTML = `
|
|
206
|
-
<div
|
|
207
|
-
|
|
208
|
-
|
|
502
|
+
<div class="project-info-item">
|
|
503
|
+
<span><i class="fas fa-folder"></i> 项目名</span>
|
|
504
|
+
<span><strong>${this.projectInfo.name}</strong></span>
|
|
505
|
+
</div>
|
|
506
|
+
<div class="project-info-item">
|
|
507
|
+
<span><i class="fas fa-map-marker-alt"></i> 路径</span>
|
|
508
|
+
<span>${this.projectInfo.path}</span>
|
|
509
|
+
</div>
|
|
510
|
+
<div class="project-info-item">
|
|
511
|
+
<span><i class="fas fa-check-circle"></i> ModernX</span>
|
|
512
|
+
<span>${this.projectInfo.hasModernX ? '✅ 已启用' : '❌ 未检测到'}</span>
|
|
513
|
+
</div>
|
|
209
514
|
`;
|
|
210
515
|
} else {
|
|
211
|
-
projectInfoEl.innerHTML =
|
|
516
|
+
projectInfoEl.innerHTML = `
|
|
517
|
+
<div class="project-info-item">
|
|
518
|
+
<span><i class="fas fa-exclamation-triangle"></i> 状态</span>
|
|
519
|
+
<span>未检测到 ModernX 项目</span>
|
|
520
|
+
</div>
|
|
521
|
+
`;
|
|
212
522
|
}
|
|
213
523
|
}
|
|
214
524
|
|
|
@@ -245,21 +555,33 @@
|
|
|
245
555
|
|
|
246
556
|
updateConnectionStatus(status) {
|
|
247
557
|
const statusEl = document.getElementById('connection-status');
|
|
248
|
-
statusEl.className = `status ${status}`;
|
|
249
|
-
statusEl.
|
|
558
|
+
statusEl.className = `status-badge ${status}`;
|
|
559
|
+
statusEl.innerHTML = status === 'connected'
|
|
560
|
+
? '<i class="fas fa-circle"></i><span>已连接</span>'
|
|
561
|
+
: '<i class="fas fa-circle"></i><span>连接断开</span>';
|
|
250
562
|
}
|
|
251
563
|
|
|
252
564
|
handleMessage(data) {
|
|
253
565
|
if (data.type === 'state') {
|
|
566
|
+
const prevState = JSON.stringify(this.currentState);
|
|
254
567
|
this.currentState = data.payload;
|
|
568
|
+
const newState = JSON.stringify(this.currentState);
|
|
569
|
+
|
|
570
|
+
if (prevState !== newState) {
|
|
571
|
+
this.stats.stateChanges++;
|
|
572
|
+
}
|
|
573
|
+
|
|
255
574
|
this.renderState();
|
|
575
|
+
this.renderDashboardState();
|
|
256
576
|
} else if (data.type === 'action') {
|
|
257
577
|
this.actions.unshift(data.payload);
|
|
258
|
-
this.actions = this.actions.slice(0,
|
|
578
|
+
this.actions = this.actions.slice(0, 100); // 只保留最近100个动作
|
|
579
|
+
this.stats.totalActions++;
|
|
259
580
|
this.renderActions();
|
|
260
581
|
} else if (data.type === 'models') {
|
|
261
582
|
this.models = data.payload;
|
|
262
583
|
this.renderModels();
|
|
584
|
+
this.renderModelsList();
|
|
263
585
|
}
|
|
264
586
|
}
|
|
265
587
|
|
|
@@ -268,46 +590,124 @@
|
|
|
268
590
|
stateEl.textContent = JSON.stringify(this.currentState, null, 2);
|
|
269
591
|
}
|
|
270
592
|
|
|
593
|
+
renderDashboardState() {
|
|
594
|
+
const stateEl = document.getElementById('dashboard-state');
|
|
595
|
+
const truncatedState = this.truncateState(this.currentState, 200);
|
|
596
|
+
stateEl.textContent = JSON.stringify(truncatedState, null, 2);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
truncateState(state, maxChars) {
|
|
600
|
+
const str = JSON.stringify(state, null, 2);
|
|
601
|
+
if (str.length <= maxChars) return state;
|
|
602
|
+
|
|
603
|
+
const truncated = str.substring(0, maxChars);
|
|
604
|
+
try {
|
|
605
|
+
return JSON.parse(truncated);
|
|
606
|
+
} catch {
|
|
607
|
+
return { message: '状态数据过大,请查看完整状态页面' };
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
271
611
|
renderActions() {
|
|
272
612
|
const actionsEl = document.getElementById('actions-list');
|
|
273
613
|
if (this.actions.length === 0) {
|
|
274
|
-
actionsEl.innerHTML =
|
|
614
|
+
actionsEl.innerHTML = `
|
|
615
|
+
<div class="empty-state">
|
|
616
|
+
<i class="fas fa-history"></i>
|
|
617
|
+
<div>暂无动作记录</div>
|
|
618
|
+
</div>
|
|
619
|
+
`;
|
|
275
620
|
return;
|
|
276
621
|
}
|
|
277
622
|
|
|
278
623
|
actionsEl.innerHTML = this.actions.map(action => `
|
|
279
624
|
<div class="action-item">
|
|
280
|
-
<div class="action-
|
|
281
|
-
|
|
282
|
-
|
|
625
|
+
<div class="action-header">
|
|
626
|
+
<div class="action-type">${action.type}</div>
|
|
627
|
+
<div class="action-time">${new Date(action.timestamp).toLocaleString()}</div>
|
|
628
|
+
</div>
|
|
629
|
+
${action.payload ? `<div class="action-payload">${JSON.stringify(action.payload)}</div>` : ''}
|
|
283
630
|
</div>
|
|
284
631
|
`).join('');
|
|
285
632
|
}
|
|
286
633
|
|
|
287
634
|
renderModels() {
|
|
288
635
|
const modelsEl = document.getElementById('models-detail');
|
|
289
|
-
const modelsListEl = document.getElementById('models-list');
|
|
290
|
-
|
|
291
636
|
if (this.models.length === 0) {
|
|
292
|
-
modelsEl.innerHTML =
|
|
293
|
-
|
|
637
|
+
modelsEl.innerHTML = `
|
|
638
|
+
<div class="empty-state">
|
|
639
|
+
<i class="fas fa-cube"></i>
|
|
640
|
+
<div>暂无模型数据</div>
|
|
641
|
+
</div>
|
|
642
|
+
`;
|
|
294
643
|
return;
|
|
295
644
|
}
|
|
296
645
|
|
|
297
|
-
// 渲染侧边栏模型列表
|
|
298
|
-
modelsListEl.innerHTML = this.models.map(model =>
|
|
299
|
-
`<div style="padding: 0.5rem 0; border-bottom: 1px solid #eee;">${model.namespace}</div>`
|
|
300
|
-
).join('');
|
|
301
|
-
|
|
302
|
-
// 渲染详细模型信息
|
|
303
646
|
modelsEl.innerHTML = this.models.map(model => `
|
|
304
|
-
<div class="
|
|
305
|
-
<
|
|
647
|
+
<div class="model-detail">
|
|
648
|
+
<div class="model-detail-header">
|
|
649
|
+
<div class="model-detail-title">
|
|
650
|
+
<i class="fas fa-cube"></i> ${model.namespace}
|
|
651
|
+
</div>
|
|
652
|
+
<div class="model-detail-actions">
|
|
653
|
+
<button class="btn btn-secondary" onclick="gui.copyModelState('${model.namespace}')">
|
|
654
|
+
<i class="fas fa-copy"></i> 复制
|
|
655
|
+
</button>
|
|
656
|
+
</div>
|
|
657
|
+
</div>
|
|
306
658
|
<div class="state-json">${JSON.stringify(model.state, null, 2)}</div>
|
|
307
659
|
</div>
|
|
308
660
|
`).join('');
|
|
309
661
|
}
|
|
310
662
|
|
|
663
|
+
renderModelsList() {
|
|
664
|
+
const modelsListEl = document.getElementById('models-list');
|
|
665
|
+
if (this.models.length === 0) {
|
|
666
|
+
modelsListEl.innerHTML = `
|
|
667
|
+
<div class="empty-state">
|
|
668
|
+
<i class="fas fa-cube"></i>
|
|
669
|
+
<div>无模型</div>
|
|
670
|
+
</div>
|
|
671
|
+
`;
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
modelsListEl.innerHTML = this.models.map(model => `
|
|
676
|
+
<div class="model-item" onclick="gui.selectModel('${model.namespace}')">
|
|
677
|
+
<div class="model-name">${model.namespace}</div>
|
|
678
|
+
<div class="model-state-count">${Object.keys(model.state || {}).length} 个状态</div>
|
|
679
|
+
</div>
|
|
680
|
+
`).join('');
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
selectModel(namespace) {
|
|
684
|
+
// 切换到模型详情标签
|
|
685
|
+
document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active'));
|
|
686
|
+
document.querySelector('[data-tab="models"]').classList.add('active');
|
|
687
|
+
|
|
688
|
+
// 显示对应内容
|
|
689
|
+
document.querySelectorAll('.tab-content').forEach(content => content.style.display = 'none');
|
|
690
|
+
document.getElementById('models-content').style.display = 'block';
|
|
691
|
+
|
|
692
|
+
// 高亮选中的模型
|
|
693
|
+
document.querySelectorAll('.model-item').forEach(item => item.classList.remove('active'));
|
|
694
|
+
event.target.closest('.model-item').classList.add('active');
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
copyModelState(namespace) {
|
|
698
|
+
const model = this.models.find(m => m.namespace === namespace);
|
|
699
|
+
if (model) {
|
|
700
|
+
navigator.clipboard.writeText(JSON.stringify(model.state, null, 2));
|
|
701
|
+
// 显示复制成功提示
|
|
702
|
+
const btn = event.target.closest('.btn');
|
|
703
|
+
const originalText = btn.innerHTML;
|
|
704
|
+
btn.innerHTML = '<i class="fas fa-check"></i> 已复制';
|
|
705
|
+
setTimeout(() => {
|
|
706
|
+
btn.innerHTML = originalText;
|
|
707
|
+
}, 2000);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
311
711
|
setupTabs() {
|
|
312
712
|
const tabs = document.querySelectorAll('.tab');
|
|
313
713
|
tabs.forEach(tab => {
|
|
@@ -326,11 +726,26 @@
|
|
|
326
726
|
});
|
|
327
727
|
});
|
|
328
728
|
}
|
|
729
|
+
|
|
730
|
+
startStatsUpdater() {
|
|
731
|
+
setInterval(() => {
|
|
732
|
+
this.updateStats();
|
|
733
|
+
}, 1000);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
updateStats() {
|
|
737
|
+
document.getElementById('total-actions').textContent = this.stats.totalActions;
|
|
738
|
+
document.getElementById('total-models').textContent = this.models.length;
|
|
739
|
+
document.getElementById('state-changes').textContent = this.stats.stateChanges;
|
|
740
|
+
|
|
741
|
+
const uptime = Math.floor((Date.now() - this.stats.connectionStartTime) / 1000);
|
|
742
|
+
document.getElementById('connection-uptime').textContent = `${uptime}s`;
|
|
743
|
+
}
|
|
329
744
|
}
|
|
330
745
|
|
|
331
746
|
// 启动 GUI
|
|
332
747
|
document.addEventListener('DOMContentLoaded', () => {
|
|
333
|
-
new ModernXGUI();
|
|
748
|
+
window.gui = new ModernXGUI();
|
|
334
749
|
});
|
|
335
750
|
</script>
|
|
336
751
|
</body>
|