nv-log-bw 1.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/DIST/nv-log-bw.js +718 -0
- package/TEST/index.html +1866 -0
- package/TEST/jsclick.html +1393 -0
- package/TEST/once.html +762 -0
- package/TOOL/cli-creat-html.js +22 -0
- package/TOOL/jsclick.html +675 -0
- package/TOOL/once.html +44 -0
- package/TOOL/tmpl.html +1148 -0
- package/com.sh +3 -0
- package/index.d.ts +489 -0
- package/index.js +1968 -0
- package/package.json +12 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const _fs = require("fs");
|
|
2
|
+
const _path = require("path");
|
|
3
|
+
|
|
4
|
+
{
|
|
5
|
+
let html = _fs.readFileSync(_path.join(__dirname,"tmpl.html")).toString();
|
|
6
|
+
let script = _fs.readFileSync(_path.join(__dirname,"../DIST/nv-log-bw.js")).toString();
|
|
7
|
+
html = html.replace(/@SCRIPT@/g,script);
|
|
8
|
+
_fs.writeFileSync(_path.join(__dirname,"../TEST/index.html"),html);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
{
|
|
12
|
+
let html = _fs.readFileSync(_path.join(__dirname,"jsclick.html")).toString();
|
|
13
|
+
let script = _fs.readFileSync(_path.join(__dirname,"../DIST/nv-log-bw.js")).toString();
|
|
14
|
+
html = html.replace(/@SCRIPT@/g,script);
|
|
15
|
+
_fs.writeFileSync(_path.join(__dirname,"../TEST/jsclick.html"),html);
|
|
16
|
+
}
|
|
17
|
+
{
|
|
18
|
+
let html = _fs.readFileSync(_path.join(__dirname,"once.html")).toString();
|
|
19
|
+
let script = _fs.readFileSync(_path.join(__dirname,"../DIST/nv-log-bw.js")).toString();
|
|
20
|
+
html = html.replace(/@SCRIPT@/g,script);
|
|
21
|
+
_fs.writeFileSync(_path.join(__dirname,"../TEST/once.html"),html);
|
|
22
|
+
}
|
|
@@ -0,0 +1,675 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>纯JS调用的日志组件范例</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
16
|
+
line-height: 1.6;
|
|
17
|
+
color: #333;
|
|
18
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
19
|
+
min-height: 100vh;
|
|
20
|
+
padding: 20px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.container {
|
|
24
|
+
max-width: 800px;
|
|
25
|
+
margin: 0 auto;
|
|
26
|
+
background: white;
|
|
27
|
+
border-radius: 20px;
|
|
28
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
29
|
+
overflow: hidden;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
header {
|
|
33
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
34
|
+
color: white;
|
|
35
|
+
padding: 40px 30px;
|
|
36
|
+
text-align: center;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
h1 {
|
|
40
|
+
font-size: 2.5em;
|
|
41
|
+
margin-bottom: 10px;
|
|
42
|
+
font-weight: 700;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.subtitle {
|
|
46
|
+
font-size: 1.2em;
|
|
47
|
+
opacity: 0.9;
|
|
48
|
+
margin-bottom: 20px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.highlight {
|
|
52
|
+
background: rgba(255, 255, 255, 0.2);
|
|
53
|
+
padding: 3px 8px;
|
|
54
|
+
border-radius: 4px;
|
|
55
|
+
font-family: 'SF Mono', Monaco, Consolas, monospace;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.demo-area {
|
|
59
|
+
padding: 30px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.control-panel {
|
|
63
|
+
display: grid;
|
|
64
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
65
|
+
gap: 20px;
|
|
66
|
+
margin-bottom: 30px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.panel-group {
|
|
70
|
+
background: #f8f9fa;
|
|
71
|
+
border-radius: 12px;
|
|
72
|
+
padding: 20px;
|
|
73
|
+
border: 1px solid #e9ecef;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.panel-group h3 {
|
|
77
|
+
color: #495057;
|
|
78
|
+
margin-bottom: 15px;
|
|
79
|
+
padding-bottom: 10px;
|
|
80
|
+
border-bottom: 2px solid #dee2e6;
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
gap: 10px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.panel-group h3 i {
|
|
87
|
+
font-size: 1.2em;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.btn-grid {
|
|
91
|
+
display: grid;
|
|
92
|
+
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
|
|
93
|
+
gap: 10px;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
button {
|
|
97
|
+
padding: 12px 20px;
|
|
98
|
+
border: none;
|
|
99
|
+
border-radius: 8px;
|
|
100
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
101
|
+
color: white;
|
|
102
|
+
cursor: pointer;
|
|
103
|
+
font-size: 14px;
|
|
104
|
+
font-weight: 500;
|
|
105
|
+
transition: all 0.3s ease;
|
|
106
|
+
display: flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
justify-content: center;
|
|
109
|
+
gap: 8px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
button:hover:not(:disabled) {
|
|
113
|
+
transform: translateY(-2px);
|
|
114
|
+
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
button:disabled {
|
|
118
|
+
opacity: 0.5;
|
|
119
|
+
cursor: not-allowed;
|
|
120
|
+
transform: none;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
button.info { background: linear-gradient(135deg, #4299e1 0%, #3182ce 100%); }
|
|
124
|
+
button.success { background: linear-gradient(135deg, #48bb78 0%, #38a169 100%); }
|
|
125
|
+
button.warning { background: linear-gradient(135deg, #ed8936 0%, #dd6b20 100%); }
|
|
126
|
+
button.error { background: linear-gradient(135deg, #f56565 0%, #e53e3e 100%); }
|
|
127
|
+
button.ignore { background: linear-gradient(135deg, #a0aec0 0%, #718096 100%); }
|
|
128
|
+
|
|
129
|
+
button.secondary {
|
|
130
|
+
background: linear-gradient(135deg, #718096 0%, #4a5568 100%);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
button.small {
|
|
134
|
+
padding: 8px 12px;
|
|
135
|
+
font-size: 12px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.output-section {
|
|
139
|
+
background: #f8f9fa;
|
|
140
|
+
border-radius: 12px;
|
|
141
|
+
padding: 20px;
|
|
142
|
+
margin-top: 20px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.output-section h3 {
|
|
146
|
+
color: #495057;
|
|
147
|
+
margin-bottom: 15px;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.code-block {
|
|
151
|
+
background: #1a202c;
|
|
152
|
+
color: #e2e8f0;
|
|
153
|
+
padding: 20px;
|
|
154
|
+
border-radius: 8px;
|
|
155
|
+
font-family: 'SF Mono', Monaco, 'Cascadia Code', Consolas, 'Courier New', monospace;
|
|
156
|
+
font-size: 13px;
|
|
157
|
+
line-height: 1.6;
|
|
158
|
+
overflow-x: auto;
|
|
159
|
+
margin: 10px 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.keyword { color: #63b3ed; }
|
|
163
|
+
.string { color: #68d391; }
|
|
164
|
+
.comment { color: #718096; }
|
|
165
|
+
.function { color: #f6e05e; }
|
|
166
|
+
.number { color: #81e6d9; }
|
|
167
|
+
|
|
168
|
+
.status-bar {
|
|
169
|
+
position: fixed;
|
|
170
|
+
bottom: 20px;
|
|
171
|
+
right: 20px;
|
|
172
|
+
background: #2d3748;
|
|
173
|
+
color: white;
|
|
174
|
+
padding: 12px 20px;
|
|
175
|
+
border-radius: 8px;
|
|
176
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
|
177
|
+
font-size: 13px;
|
|
178
|
+
display: flex;
|
|
179
|
+
align-items: center;
|
|
180
|
+
gap: 10px;
|
|
181
|
+
z-index: 1000;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.status-bar.hidden {
|
|
185
|
+
display: none;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.log-message {
|
|
189
|
+
background: white;
|
|
190
|
+
border-left: 4px solid #4299e1;
|
|
191
|
+
padding: 10px 15px;
|
|
192
|
+
margin: 10px 0;
|
|
193
|
+
border-radius: 4px;
|
|
194
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
195
|
+
font-size: 13px;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.log-message.success { border-left-color: #48bb78; }
|
|
199
|
+
.log-message.warning { border-left-color: #ed8936; }
|
|
200
|
+
.log-message.error { border-left-color: #f56565; }
|
|
201
|
+
.log-message.ignore { border-left-color: #a0aec0; }
|
|
202
|
+
|
|
203
|
+
.stats {
|
|
204
|
+
display: grid;
|
|
205
|
+
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
|
206
|
+
gap: 10px;
|
|
207
|
+
margin: 20px 0;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.stat-item {
|
|
211
|
+
background: white;
|
|
212
|
+
padding: 15px;
|
|
213
|
+
border-radius: 8px;
|
|
214
|
+
text-align: center;
|
|
215
|
+
border: 1px solid #e2e8f0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.stat-label {
|
|
219
|
+
font-size: 12px;
|
|
220
|
+
color: #718096;
|
|
221
|
+
text-transform: uppercase;
|
|
222
|
+
letter-spacing: 0.5px;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.stat-value {
|
|
226
|
+
font-size: 1.5em;
|
|
227
|
+
font-weight: 700;
|
|
228
|
+
margin-top: 5px;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.stat-value.info { color: #4299e1; }
|
|
232
|
+
.stat-value.success { color: #48bb78; }
|
|
233
|
+
.stat-value.warning { color: #ed8936; }
|
|
234
|
+
.stat-value.error { color: #f56565; }
|
|
235
|
+
.stat-value.ignore { color: #a0aec0; }
|
|
236
|
+
.stat-value.total { color: #2d3748; }
|
|
237
|
+
|
|
238
|
+
.divider {
|
|
239
|
+
height: 1px;
|
|
240
|
+
background: linear-gradient(to right, transparent, #e2e8f0, transparent);
|
|
241
|
+
margin: 20px 0;
|
|
242
|
+
}
|
|
243
|
+
</style>
|
|
244
|
+
</head>
|
|
245
|
+
<body>
|
|
246
|
+
<div class="container">
|
|
247
|
+
<header>
|
|
248
|
+
<h1>📊 纯 JavaScript 调用的日志组件</h1>
|
|
249
|
+
<p class="subtitle">无需显示界面,直接在代码中使用的日志组件</p>
|
|
250
|
+
</header>
|
|
251
|
+
|
|
252
|
+
<div class="demo-area">
|
|
253
|
+
<!-- 隐藏的日志组件容器 -->
|
|
254
|
+
<div id="loggerContainer" style="display: none;"></div>
|
|
255
|
+
|
|
256
|
+
<div class="control-panel">
|
|
257
|
+
<!-- 日志操作 -->
|
|
258
|
+
<div class="panel-group">
|
|
259
|
+
<h3><i>📝</i> 添加日志</h3>
|
|
260
|
+
<div class="btn-grid">
|
|
261
|
+
<button class="info" onclick="logInfo()">信息日志</button>
|
|
262
|
+
<button class="success" onclick="logSuccess()">成功日志</button>
|
|
263
|
+
<button class="warning" onclick="logWarning()">警告日志</button>
|
|
264
|
+
<button class="error" onclick="logError()">错误日志</button>
|
|
265
|
+
<button class="ignore" onclick="logIgnore()">忽略日志</button>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
|
|
269
|
+
<!-- 组件控制 -->
|
|
270
|
+
<div class="panel-group">
|
|
271
|
+
<h3><i>⚙️</i> 组件控制</h3>
|
|
272
|
+
<div class="btn-grid">
|
|
273
|
+
<button onclick="toggleLoggerVisibility()">👁️ 显示/隐藏界面</button>
|
|
274
|
+
<button onclick="clearLogs()">🗑️ 清空日志</button>
|
|
275
|
+
<button onclick="exportLogs()">📥 导出日志</button>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
|
|
280
|
+
<div class="divider"></div>
|
|
281
|
+
|
|
282
|
+
<!-- 数据导入 -->
|
|
283
|
+
<div class="panel-group">
|
|
284
|
+
<h3><i>📤</i> 数据导入</h3>
|
|
285
|
+
<div class="btn-grid" style="grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));">
|
|
286
|
+
<button onclick="importJson()">导入JSON</button>
|
|
287
|
+
<button onclick="importText()">导入文本</button>
|
|
288
|
+
<button onclick="importFromAPI()">从API导入</button>
|
|
289
|
+
<button onclick="importRandomLogs()">随机日志</button>
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
|
|
293
|
+
<div class="divider"></div>
|
|
294
|
+
|
|
295
|
+
<!-- 统计分析 -->
|
|
296
|
+
<div class="panel-group">
|
|
297
|
+
<h3><i>📊</i> 统计分析</h3>
|
|
298
|
+
<div class="stats" id="statsContainer">
|
|
299
|
+
<!-- 统计信息会动态更新 -->
|
|
300
|
+
</div>
|
|
301
|
+
<div class="btn-grid">
|
|
302
|
+
<button onclick="updateStats()">更新统计</button>
|
|
303
|
+
<button onclick="getAllLogs()">获取所有日志</button>
|
|
304
|
+
<button onclick="filterLogs()">按类型过滤</button>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
|
|
308
|
+
<div class="divider"></div>
|
|
309
|
+
|
|
310
|
+
<!-- 代码示例 -->
|
|
311
|
+
<div class="output-section">
|
|
312
|
+
<h3>JavaScript 代码示例</h3>
|
|
313
|
+
<div class="code-block">
|
|
314
|
+
<span class="comment">// 1. 创建和配置日志组件</span><br>
|
|
315
|
+
<span class="keyword">const</span> logger = <span class="keyword">document</span>.createElement(<span class="string">'nv-log-viewer'</span>);<br>
|
|
316
|
+
logger.setAttribute(<span class="string">'id'</span>, <span class="string">'hiddenLogger'</span>);<br>
|
|
317
|
+
logger.setAttribute(<span class="string">'max-logs'</span>, <span class="string">'200'</span>);<br>
|
|
318
|
+
logger.setAttribute(<span class="string">'theme'</span>, <span class="string">'dark'</span>);<br>
|
|
319
|
+
logger.setAttribute(<span class="string">'show-stats'</span>, <span class="string">'false'</span>);<br>
|
|
320
|
+
logger.style.display = <span class="string">'none'</span>; <span class="comment">// 隐藏界面</span><br><br>
|
|
321
|
+
<span class="keyword">document</span>.body.appendChild(logger);<br><br>
|
|
322
|
+
<span class="comment">// 2. 添加日志</span><br>
|
|
323
|
+
logger.addLog(<span class="string">'应用启动成功'</span>, <span class="string">'success'</span>);<br>
|
|
324
|
+
logger.addLog(<span class="string">'正在加载数据...'</span>, <span class="string">'info'</span>);<br>
|
|
325
|
+
logger.addLog({ <span class="keyword">error</span>: <span class="string">'404'</span>, <span class="keyword">message</span>: <span class="string">'页面不存在'</span> }, <span class="string">'error'</span>);<br><br>
|
|
326
|
+
<span class="comment">// 3. 获取和分析日志</span><br>
|
|
327
|
+
<span class="keyword">const</span> logs = logger.getLogs();<br>
|
|
328
|
+
<span class="keyword">const</span> errors = logger.getLogsByType(<span class="string">'error'</span>);<br>
|
|
329
|
+
<span class="keyword">const</span> stats = logger.getStats();<br><br>
|
|
330
|
+
<span class="comment">// 4. 导出日志</span><br>
|
|
331
|
+
logger.exportLogs(<span class="string">'json'</span>); <span class="comment">// 导出为JSON文件</span><br>
|
|
332
|
+
<span class="function">await</span> logger.copyLogs(); <span class="comment">// 复制到剪贴板</span>
|
|
333
|
+
</div>
|
|
334
|
+
</div>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
|
|
338
|
+
<!-- 状态栏 -->
|
|
339
|
+
<div class="status-bar hidden" id="statusBar">
|
|
340
|
+
<span id="statusMessage">状态信息</span>
|
|
341
|
+
</div>
|
|
342
|
+
|
|
343
|
+
<script>
|
|
344
|
+
@SCRIPT@
|
|
345
|
+
</script>
|
|
346
|
+
<script>
|
|
347
|
+
// 全局变量
|
|
348
|
+
let logger = null;
|
|
349
|
+
let isLoggerVisible = false;
|
|
350
|
+
let logCount = 0;
|
|
351
|
+
|
|
352
|
+
// 初始化隐藏的日志组件
|
|
353
|
+
function initHiddenLogger() {
|
|
354
|
+
// 创建日志组件
|
|
355
|
+
logger = document.createElement('nv-log-viewer');
|
|
356
|
+
logger.id = 'hiddenLogger';
|
|
357
|
+
|
|
358
|
+
// 配置组件属性
|
|
359
|
+
logger.setAttribute('max-logs', '200');
|
|
360
|
+
logger.setAttribute('theme', 'dark');
|
|
361
|
+
logger.setAttribute('show-time', 'true');
|
|
362
|
+
logger.setAttribute('time-format', 'HH:mm:ss');
|
|
363
|
+
logger.setAttribute('auto-scroll', 'true');
|
|
364
|
+
logger.setAttribute('show-stats', 'false'); // 不显示统计
|
|
365
|
+
|
|
366
|
+
// 完全隐藏组件
|
|
367
|
+
logger.style.display = 'none';
|
|
368
|
+
logger.style.position = 'fixed';
|
|
369
|
+
logger.style.left = '-9999px';
|
|
370
|
+
logger.style.top = '-9999px';
|
|
371
|
+
logger.style.width = '0';
|
|
372
|
+
logger.style.height = '0';
|
|
373
|
+
logger.style.overflow = 'hidden';
|
|
374
|
+
logger.style.opacity = '0';
|
|
375
|
+
logger.style.pointerEvents = 'none';
|
|
376
|
+
logger.style.visibility = 'hidden';
|
|
377
|
+
|
|
378
|
+
// 添加到容器
|
|
379
|
+
document.getElementById('loggerContainer').appendChild(logger);
|
|
380
|
+
|
|
381
|
+
// 监听事件
|
|
382
|
+
logger.addEventListener('nv-log-add', (e) => {
|
|
383
|
+
logCount = e.detail.total;
|
|
384
|
+
updateStatsDisplay();
|
|
385
|
+
showStatus(`添加日志: ${e.detail.log.message.substring(0, 30)}...`);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
logger.addEventListener('nv-log-clear', (e) => {
|
|
389
|
+
logCount = 0;
|
|
390
|
+
updateStatsDisplay();
|
|
391
|
+
showStatus(`清空了 ${e.detail.clearedCount} 条日志`, 'success');
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
// 添加初始日志
|
|
395
|
+
setTimeout(() => {
|
|
396
|
+
logger.addLog('隐藏的日志组件已初始化', 'success');
|
|
397
|
+
logger.addLog('组件界面被隐藏,但功能完整', 'info');
|
|
398
|
+
logger.addLog('可以通过JavaScript API完全控制', 'info');
|
|
399
|
+
}, 100);
|
|
400
|
+
|
|
401
|
+
return logger;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// 显示状态消息
|
|
405
|
+
function showStatus(message, type = 'info') {
|
|
406
|
+
const statusBar = document.getElementById('statusBar');
|
|
407
|
+
const statusMessage = document.getElementById('statusMessage');
|
|
408
|
+
|
|
409
|
+
statusMessage.textContent = message;
|
|
410
|
+
statusBar.classList.remove('hidden');
|
|
411
|
+
|
|
412
|
+
// 设置颜色
|
|
413
|
+
statusBar.style.background = type === 'success' ? '#38a169' :
|
|
414
|
+
type === 'error' ? '#e53e3e' :
|
|
415
|
+
type === 'warning' ? '#d69e2e' : '#2d3748';
|
|
416
|
+
|
|
417
|
+
// 3秒后隐藏
|
|
418
|
+
setTimeout(() => {
|
|
419
|
+
statusBar.classList.add('hidden');
|
|
420
|
+
}, 3000);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// 更新统计显示
|
|
424
|
+
function updateStatsDisplay() {
|
|
425
|
+
if (!logger) return;
|
|
426
|
+
|
|
427
|
+
const stats = logger.getStats();
|
|
428
|
+
const statsContainer = document.getElementById('statsContainer');
|
|
429
|
+
|
|
430
|
+
statsContainer.innerHTML = `
|
|
431
|
+
<div class="stat-item">
|
|
432
|
+
<div class="stat-label">总计</div>
|
|
433
|
+
<div class="stat-value total">${stats.total}</div>
|
|
434
|
+
</div>
|
|
435
|
+
<div class="stat-item">
|
|
436
|
+
<div class="stat-label">信息</div>
|
|
437
|
+
<div class="stat-value info">${stats.info}</div>
|
|
438
|
+
</div>
|
|
439
|
+
<div class="stat-item">
|
|
440
|
+
<div class="stat-label">成功</div>
|
|
441
|
+
<div class="stat-value success">${stats.success}</div>
|
|
442
|
+
</div>
|
|
443
|
+
<div class="stat-item">
|
|
444
|
+
<div class="stat-label">警告</div>
|
|
445
|
+
<div class="stat-value warning">${stats.warning}</div>
|
|
446
|
+
</div>
|
|
447
|
+
<div class="stat-item">
|
|
448
|
+
<div class="stat-label">错误</div>
|
|
449
|
+
<div class="stat-value error">${stats.error}</div>
|
|
450
|
+
</div>
|
|
451
|
+
<div class="stat-item">
|
|
452
|
+
<div class="stat-label">忽略</div>
|
|
453
|
+
<div class="stat-value ignore">${stats.ignore}</div>
|
|
454
|
+
</div>
|
|
455
|
+
`;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// 日志操作函数
|
|
459
|
+
function logInfo() {
|
|
460
|
+
logger.addLog(`这是第 ${logCount + 1} 条信息日志`, 'info');
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function logSuccess() {
|
|
464
|
+
logger.addLog(`操作成功完成 - ${new Date().toLocaleTimeString()}`, 'success');
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function logWarning() {
|
|
468
|
+
logger.addLog(`警告:资源使用率过高 (${Math.random() * 100 | 0}%)`, 'warning');
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function logError() {
|
|
472
|
+
const errors = [
|
|
473
|
+
'数据库连接失败',
|
|
474
|
+
'网络请求超时',
|
|
475
|
+
'文件读取错误',
|
|
476
|
+
'权限验证失败',
|
|
477
|
+
'内存溢出异常'
|
|
478
|
+
];
|
|
479
|
+
const error = errors[Math.floor(Math.random() * errors.length)];
|
|
480
|
+
logger.addLog(`错误: ${error}`, 'error');
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function logIgnore() {
|
|
484
|
+
logger.addLog(`忽略重复记录 #${Math.floor(Math.random() * 1000)}`, 'ignore');
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// 组件控制函数
|
|
488
|
+
function toggleLoggerVisibility() {
|
|
489
|
+
if (!isLoggerVisible) {
|
|
490
|
+
// 显示组件
|
|
491
|
+
logger.style.display = 'block';
|
|
492
|
+
logger.style.position = 'fixed';
|
|
493
|
+
logger.style.left = '50%';
|
|
494
|
+
logger.style.top = '50%';
|
|
495
|
+
logger.style.transform = 'translate(-50%, -50%)';
|
|
496
|
+
logger.style.width = '600px';
|
|
497
|
+
logger.style.height = '400px';
|
|
498
|
+
logger.style.zIndex = '9999';
|
|
499
|
+
logger.style.opacity = '1';
|
|
500
|
+
logger.style.visibility = 'visible';
|
|
501
|
+
logger.style.pointerEvents = 'auto';
|
|
502
|
+
logger.style.boxShadow = '0 20px 60px rgba(0, 0, 0, 0.3)';
|
|
503
|
+
isLoggerVisible = true;
|
|
504
|
+
showStatus('日志界面已显示', 'success');
|
|
505
|
+
} else {
|
|
506
|
+
// 隐藏组件
|
|
507
|
+
logger.style.display = 'none';
|
|
508
|
+
isLoggerVisible = false;
|
|
509
|
+
showStatus('日志界面已隐藏', 'info');
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function clearLogs() {
|
|
514
|
+
if (confirm('确定要清空所有日志吗?')) {
|
|
515
|
+
logger.clearLogs();
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function exportLogs() {
|
|
520
|
+
logger.exportLogs('json');
|
|
521
|
+
showStatus('日志已导出为JSON文件', 'success');
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// 导入函数
|
|
525
|
+
function importJson() {
|
|
526
|
+
const jsonData = {
|
|
527
|
+
exportTime: new Date().toISOString(),
|
|
528
|
+
totalLogs: 3,
|
|
529
|
+
logs: [
|
|
530
|
+
{
|
|
531
|
+
time: Date.now() - 10000,
|
|
532
|
+
type: 'info',
|
|
533
|
+
message: '从JSON导入的日志1'
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
time: Date.now() - 5000,
|
|
537
|
+
type: 'success',
|
|
538
|
+
message: '从JSON导入的日志2'
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
time: Date.now(),
|
|
542
|
+
type: 'error',
|
|
543
|
+
message: '从JSON导入的日志3'
|
|
544
|
+
}
|
|
545
|
+
]
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
logger.importLogs(JSON.stringify(jsonData), 'json')
|
|
549
|
+
.then(result => {
|
|
550
|
+
showStatus(`从JSON导入了 ${result.count} 条日志`, 'success');
|
|
551
|
+
})
|
|
552
|
+
.catch(error => {
|
|
553
|
+
showStatus(`导入失败: ${error.message}`, 'error');
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function importText() {
|
|
558
|
+
const now = new Date();
|
|
559
|
+
const time1 = now.toLocaleTimeString('zh-CN', { hour12: false });
|
|
560
|
+
const time2 = new Date(now.getTime() - 5000).toLocaleTimeString('zh-CN', { hour12: false });
|
|
561
|
+
|
|
562
|
+
const textData = `[${time2}] [INFO] 从文本导入的日志1
|
|
563
|
+
[${time1}] [ERROR] 从文本导入的日志2
|
|
564
|
+
[${new Date(now.getTime() - 2000).toLocaleTimeString('zh-CN', { hour12: false })}] [SUCCESS] 从文本导入的日志3`;
|
|
565
|
+
|
|
566
|
+
logger.importLogs(textData, 'text')
|
|
567
|
+
.then(result => {
|
|
568
|
+
showStatus(`从文本导入了 ${result.count} 条日志`, 'success');
|
|
569
|
+
})
|
|
570
|
+
.catch(error => {
|
|
571
|
+
showStatus(`导入失败: ${error.message}`, 'error');
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
async function importFromAPI() {
|
|
576
|
+
showStatus('正在从模拟API获取数据...', 'info');
|
|
577
|
+
|
|
578
|
+
// 模拟API请求
|
|
579
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
580
|
+
|
|
581
|
+
const mockApiData = {
|
|
582
|
+
logs: [
|
|
583
|
+
{
|
|
584
|
+
timestamp: Date.now() - 15000,
|
|
585
|
+
level: 'info',
|
|
586
|
+
msg: '从API获取的用户数据'
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
timestamp: Date.now() - 8000,
|
|
590
|
+
level: 'success',
|
|
591
|
+
text: 'API请求成功完成'
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
timestamp: Date.now(),
|
|
595
|
+
level: 'warning',
|
|
596
|
+
message: 'API响应时间过长'
|
|
597
|
+
}
|
|
598
|
+
]
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
logger.importLogs(JSON.stringify(mockApiData), 'json')
|
|
602
|
+
.then(result => {
|
|
603
|
+
showStatus(`从API导入了 ${result.count} 条日志`, 'success');
|
|
604
|
+
})
|
|
605
|
+
.catch(error => {
|
|
606
|
+
showStatus(`API导入失败: ${error.message}`, 'error');
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function importRandomLogs() {
|
|
611
|
+
const types = ['info', 'success', 'warning', 'error', 'ignore'];
|
|
612
|
+
const messages = [
|
|
613
|
+
'系统初始化完成',
|
|
614
|
+
'数据处理成功',
|
|
615
|
+
'缓存命中率较低',
|
|
616
|
+
'网络连接异常',
|
|
617
|
+
'跳过无效记录',
|
|
618
|
+
'用户登录验证',
|
|
619
|
+
'文件上传完成',
|
|
620
|
+
'内存使用警告',
|
|
621
|
+
'数据库查询错误',
|
|
622
|
+
'任务调度完成'
|
|
623
|
+
];
|
|
624
|
+
|
|
625
|
+
for (let i = 0; i < 5; i++) {
|
|
626
|
+
const type = types[Math.floor(Math.random() * types.length)];
|
|
627
|
+
const message = `${messages[Math.floor(Math.random() * messages.length)]} #${i + 1}`;
|
|
628
|
+
const time = Date.now() - Math.floor(Math.random() * 30000);
|
|
629
|
+
|
|
630
|
+
logger.addLog(message, type, time);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
showStatus('已添加5条随机日志', 'success');
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// 统计分析函数
|
|
637
|
+
function updateStats() {
|
|
638
|
+
const stats = logger.getStats();
|
|
639
|
+
showStatus(`统计更新: 总计 ${stats.total} 条日志`, 'info');
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
function getAllLogs() {
|
|
643
|
+
const logs = logger.getLogs();
|
|
644
|
+
const last5 = logs.slice(-5);
|
|
645
|
+
|
|
646
|
+
const logList = last5.map(log =>
|
|
647
|
+
`[${new Date(log.time).toLocaleTimeString()}] [${log.type.toUpperCase()}] ${log.message}`
|
|
648
|
+
).join('\n');
|
|
649
|
+
|
|
650
|
+
alert(`最后5条日志:\n\n${logList}`);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
function filterLogs() {
|
|
654
|
+
const errors = logger.getLogsByType('error');
|
|
655
|
+
const warnings = logger.getLogsByType('warning');
|
|
656
|
+
|
|
657
|
+
alert(`过滤结果:\n错误: ${errors.length} 条\n警告: ${warnings.length} 条`);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// 页面加载完成后初始化
|
|
661
|
+
window.addEventListener('DOMContentLoaded', () => {
|
|
662
|
+
// 初始化隐藏的日志组件
|
|
663
|
+
logger = initHiddenLogger();
|
|
664
|
+
|
|
665
|
+
// 更新统计显示
|
|
666
|
+
setTimeout(() => {
|
|
667
|
+
updateStatsDisplay();
|
|
668
|
+
}, 500);
|
|
669
|
+
|
|
670
|
+
// 显示初始化消息
|
|
671
|
+
showStatus('隐藏的日志组件已就绪,可通过JavaScript API调用', 'success');
|
|
672
|
+
});
|
|
673
|
+
</script>
|
|
674
|
+
</body>
|
|
675
|
+
</html>
|