326 lines
7.5 KiB
JavaScript
326 lines
7.5 KiB
JavaScript
const { BrowserWindow } = require('electron');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
|
|
/**
|
|
* 日志窗口管理器
|
|
* 显示 MySQL 和 Spring Boot 的实时日志
|
|
*/
|
|
class LogWindowManager {
|
|
constructor() {
|
|
this.logWindow = null;
|
|
this.logs = [];
|
|
this.maxLogs = 1000; // 最多保留1000条日志
|
|
}
|
|
|
|
/**
|
|
* 创建日志窗口
|
|
*/
|
|
createLogWindow() {
|
|
this.logWindow = new BrowserWindow({
|
|
width: 900,
|
|
height: 600,
|
|
title: 'NPQS9100 - 服务日志',
|
|
backgroundColor: '#1e1e1e',
|
|
webPreferences: {
|
|
nodeIntegration: true,
|
|
contextIsolation: false
|
|
}
|
|
});
|
|
|
|
// 加载日志页面
|
|
const logHtml = this.generateLogHTML();
|
|
this.logWindow.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(logHtml)}`);
|
|
|
|
// 窗口关闭事件 - 只清理引用,不退出应用
|
|
this.logWindow.on('closed', () => {
|
|
console.log('[LogWindow] Log window closed by user');
|
|
this.logWindow = null;
|
|
});
|
|
|
|
// 防止日志窗口关闭时退出应用(但允许隐藏)
|
|
this.closeHandler = (event) => {
|
|
// 只是隐藏窗口,不是真正关闭
|
|
// 这样可以随时再打开
|
|
event.preventDefault();
|
|
this.logWindow.hide();
|
|
console.log('[LogWindow] Log window hidden');
|
|
};
|
|
|
|
this.logWindow.on('close', this.closeHandler);
|
|
|
|
return this.logWindow;
|
|
}
|
|
|
|
/**
|
|
* 生成日志HTML页面
|
|
*/
|
|
generateLogHTML() {
|
|
return `
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>NPQS9100 服务日志</title>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
body {
|
|
font-family: 'Consolas', 'Courier New', monospace;
|
|
background: #1e1e1e;
|
|
color: #d4d4d4;
|
|
padding: 10px;
|
|
overflow: hidden;
|
|
}
|
|
.header {
|
|
background: #2d2d30;
|
|
padding: 10px;
|
|
border-radius: 4px;
|
|
margin-bottom: 10px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
.title {
|
|
font-size: 14px;
|
|
font-weight: bold;
|
|
color: #4ec9b0;
|
|
}
|
|
.controls button {
|
|
background: #0e639c;
|
|
color: white;
|
|
border: none;
|
|
padding: 5px 10px;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
margin-left: 5px;
|
|
font-size: 12px;
|
|
}
|
|
.controls button:hover {
|
|
background: #1177bb;
|
|
}
|
|
.log-container {
|
|
background: #1e1e1e;
|
|
border: 1px solid #3e3e42;
|
|
border-radius: 4px;
|
|
height: calc(100vh - 70px);
|
|
overflow-y: auto;
|
|
padding: 10px;
|
|
font-size: 12px;
|
|
line-height: 1.5;
|
|
}
|
|
.log-entry {
|
|
margin-bottom: 2px;
|
|
white-space: pre-wrap;
|
|
word-wrap: break-word;
|
|
}
|
|
.log-mysql { color: #4ec9b0; }
|
|
.log-java { color: #dcdcaa; }
|
|
.log-system { color: #569cd6; }
|
|
.log-error { color: #f48771; }
|
|
.log-warn { color: #ce9178; }
|
|
.log-success { color: #608b4e; }
|
|
.timestamp {
|
|
color: #858585;
|
|
margin-right: 8px;
|
|
}
|
|
::-webkit-scrollbar {
|
|
width: 8px;
|
|
}
|
|
::-webkit-scrollbar-track {
|
|
background: #1e1e1e;
|
|
}
|
|
::-webkit-scrollbar-thumb {
|
|
background: #424242;
|
|
border-radius: 4px;
|
|
}
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: #4e4e4e;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="header">
|
|
<div class="title">📝 NPQS9100 服务日志监控</div>
|
|
<div class="controls">
|
|
<button onclick="clearLogs()">清空日志</button>
|
|
<button onclick="toggleAutoScroll()">自动滚动: <span id="autoScrollStatus">开</span></button>
|
|
</div>
|
|
</div>
|
|
<div class="log-container" id="logContainer"></div>
|
|
|
|
<script>
|
|
const { ipcRenderer } = require('electron');
|
|
const logContainer = document.getElementById('logContainer');
|
|
let autoScroll = true;
|
|
|
|
// 接收日志
|
|
ipcRenderer.on('log-message', (event, data) => {
|
|
addLog(data);
|
|
});
|
|
|
|
function addLog(data) {
|
|
const entry = document.createElement('div');
|
|
entry.className = 'log-entry';
|
|
|
|
const timestamp = document.createElement('span');
|
|
timestamp.className = 'timestamp';
|
|
timestamp.textContent = data.timestamp;
|
|
entry.appendChild(timestamp);
|
|
|
|
const message = document.createElement('span');
|
|
message.className = \`log-\${data.type}\`;
|
|
message.textContent = data.message;
|
|
entry.appendChild(message);
|
|
|
|
logContainer.appendChild(entry);
|
|
|
|
// 自动滚动到底部
|
|
if (autoScroll) {
|
|
logContainer.scrollTop = logContainer.scrollHeight;
|
|
}
|
|
|
|
// 限制日志条数
|
|
while (logContainer.children.length > 1000) {
|
|
logContainer.removeChild(logContainer.firstChild);
|
|
}
|
|
}
|
|
|
|
function clearLogs() {
|
|
logContainer.innerHTML = '';
|
|
}
|
|
|
|
function toggleAutoScroll() {
|
|
autoScroll = !autoScroll;
|
|
document.getElementById('autoScrollStatus').textContent = autoScroll ? '开' : '关';
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* 添加日志
|
|
*/
|
|
addLog(type, message) {
|
|
const timestamp = new Date().toLocaleTimeString();
|
|
const logEntry = {
|
|
timestamp,
|
|
type,
|
|
message
|
|
};
|
|
|
|
this.logs.push(logEntry);
|
|
|
|
// 限制日志数量
|
|
if (this.logs.length > this.maxLogs) {
|
|
this.logs.shift();
|
|
}
|
|
|
|
// 发送到窗口
|
|
if (this.logWindow && !this.logWindow.isDestroyed()) {
|
|
this.logWindow.webContents.send('log-message', logEntry);
|
|
}
|
|
|
|
// 同时输出到控制台
|
|
console.log(`[${type.toUpperCase()}] ${message}`);
|
|
}
|
|
|
|
/**
|
|
* 显示日志窗口
|
|
*/
|
|
show() {
|
|
if (!this.logWindow || this.logWindow.isDestroyed()) {
|
|
// 窗口已被销毁,重新创建
|
|
console.log('[LogWindow] Recreating log window...');
|
|
this.createLogWindow();
|
|
|
|
// 重新发送历史日志
|
|
this.logs.forEach(log => {
|
|
this.logWindow.webContents.send('log-message', log);
|
|
});
|
|
} else {
|
|
this.logWindow.show();
|
|
this.logWindow.focus();
|
|
console.log('[LogWindow] Log window shown');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 隐藏日志窗口
|
|
*/
|
|
hide() {
|
|
if (this.logWindow && !this.logWindow.isDestroyed()) {
|
|
this.logWindow.hide();
|
|
console.log('[LogWindow] Log window hidden');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查日志窗口是否可见
|
|
*/
|
|
isVisible() {
|
|
return this.logWindow && !this.logWindow.isDestroyed() && this.logWindow.isVisible();
|
|
}
|
|
|
|
/**
|
|
* 切换日志窗口显示/隐藏
|
|
*/
|
|
toggle() {
|
|
if (this.isVisible()) {
|
|
this.hide();
|
|
} else {
|
|
this.show();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 关闭日志窗口(真正销毁)
|
|
*/
|
|
close() {
|
|
if (this.logWindow && !this.logWindow.isDestroyed()) {
|
|
try {
|
|
// 移除 close 事件监听,允许真正关闭
|
|
if (this.closeHandler) {
|
|
this.logWindow.removeListener('close', this.closeHandler);
|
|
}
|
|
this.logWindow.removeAllListeners('close');
|
|
this.logWindow.removeAllListeners('closed');
|
|
|
|
// 强制销毁窗口
|
|
this.logWindow.destroy();
|
|
console.log('[LogWindow] Log window destroyed');
|
|
} catch (error) {
|
|
console.error('[LogWindow] Error closing log window:', error);
|
|
} finally {
|
|
this.logWindow = null;
|
|
this.closeHandler = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取所有日志
|
|
*/
|
|
getLogs() {
|
|
return this.logs;
|
|
}
|
|
|
|
/**
|
|
* 清空日志
|
|
*/
|
|
clearLogs() {
|
|
this.logs = [];
|
|
if (this.logWindow && !this.logWindow.isDestroyed()) {
|
|
this.logWindow.webContents.send('clear-logs');
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = LogWindowManager;
|
|
|