[add] 畫面調整
This commit is contained in:
38
src/electron/index.css
Normal file
38
src/electron/index.css
Normal file
@@ -0,0 +1,38 @@
|
||||
/* index.css */
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
#log-container {
|
||||
width: 70%;
|
||||
background-color: black;
|
||||
color: green;
|
||||
padding: 10px;
|
||||
overflow-y: scroll; /* 允许垂直滚动 */
|
||||
white-space: pre-wrap;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
box-sizing: border-box; /* 包括 padding 在内的计算方式 */
|
||||
}
|
||||
|
||||
#control-panel {
|
||||
width: 30%;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
background-color: #f0f0f0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
input {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
29
src/electron/index.html
Normal file
29
src/electron/index.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
|
||||
<head>
|
||||
<title>SD Server Control</title>
|
||||
<link rel="stylesheet" href="index.css">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="log-container">
|
||||
<div id="log"></div>
|
||||
</div>
|
||||
|
||||
<div id="control-panel">
|
||||
<h2>Control Panel</h2>
|
||||
<label for="port">Port:</label>
|
||||
<input type="number" id="port" value="8080">
|
||||
<button id="startBtn">啟動</button>
|
||||
<button id="stopBtn">關閉</button>
|
||||
<button id="devToolsBtn">DevTools</button>
|
||||
<p id="status">Status: Waiting for actions...</p>
|
||||
</div>
|
||||
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
117
src/electron/main.ts
Normal file
117
src/electron/main.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
// src/main.ts
|
||||
import dotenv from 'dotenv';
|
||||
import { app, BrowserWindow, ipcMain } from 'electron';
|
||||
import * as path from 'path';
|
||||
import { WebSocketServer } from 'ws';
|
||||
|
||||
// Load environment variables from .env file
|
||||
dotenv.config();
|
||||
|
||||
let server: WebSocketServer | null = null;
|
||||
let port: number = process.env.PORT ? parseInt(process.env.PORT, 10) : 8080; // 默认端口为 8080
|
||||
|
||||
function createWindow() {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
// contextIsolation: false, // 使渲染進程能夠使用 Node.js
|
||||
// nodeIntegration: true, // 使渲染進程可以使用 Node.js 模組
|
||||
},
|
||||
});
|
||||
|
||||
win.loadFile(path.join(__dirname, 'index.html'));
|
||||
// win.webContents.openDevTools();
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
let mainWindow: BrowserWindow | null = null;
|
||||
|
||||
// Create a function to send log messages to the renderer
|
||||
function sendLogToRenderer(window: BrowserWindow, message: string) {
|
||||
window.webContents.send('log-message', message);
|
||||
}
|
||||
|
||||
// 重寫 console.log 方法以便將訊息發送到渲染進程
|
||||
const originalConsoleLog = console.log;
|
||||
console.log = (...args: any[]) => {
|
||||
const message = args.join(' ');
|
||||
originalConsoleLog(message); // 保留原始行為
|
||||
if (BrowserWindow.getAllWindows().length > 0) {
|
||||
sendLogToRenderer(BrowserWindow.getAllWindows()[0], message); // 發送訊息到渲染進程
|
||||
}
|
||||
};
|
||||
|
||||
app.whenReady().then(() => {
|
||||
mainWindow = createWindow();
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
// 启动 WebSocket 服务器
|
||||
ipcMain.on('start-websocket', (event, portNumber: number) => {
|
||||
if (server) {
|
||||
server.close();
|
||||
}
|
||||
|
||||
port = portNumber || 8080;
|
||||
|
||||
server = new WebSocketServer({ port: port });
|
||||
|
||||
server.on('connection', (socket, request) => {
|
||||
const ip = request.socket.remoteAddress.replace("::ffff:", "") || 'Unknown IP';
|
||||
console.log(`Client connected from IP: ${ip}`);
|
||||
socket.send('Welcome to the WebSocket server');
|
||||
|
||||
socket.on('message', (message: string) => {
|
||||
console.log(`[RPC] 收到client呼叫: ${message}`);
|
||||
socket.send(`Server received your message: ${message}`);
|
||||
console.log(`[RPC] 回傳client呼叫: ${message}`);
|
||||
});
|
||||
|
||||
socket.on('close', () => {
|
||||
console.log('Client disconnected');
|
||||
});
|
||||
});
|
||||
|
||||
event.reply('websocket-status', `WebSocket server started on port ${port}`);
|
||||
});
|
||||
|
||||
// 关闭 WebSocket 服务器
|
||||
ipcMain.on('stop-websocket', (event) => {
|
||||
if (server) {
|
||||
server.clients.forEach(client => {
|
||||
if (client.readyState === 1) {
|
||||
client.close();
|
||||
}
|
||||
});
|
||||
server.close((err) => {
|
||||
if (err) {
|
||||
event.reply('websocket-status', 'Failed to stop WebSocket server');
|
||||
} else {
|
||||
event.reply('websocket-status', 'WebSocket server stopped');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
event.reply('websocket-status', 'No WebSocket server is running');
|
||||
}
|
||||
});
|
||||
|
||||
// 打开开发者工具
|
||||
ipcMain.on('open-devtools', () => {
|
||||
mainWindow.webContents.openDevTools();
|
||||
});
|
||||
13
src/electron/preload.ts
Normal file
13
src/electron/preload.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
// src/preload.ts
|
||||
import { contextBridge, ipcRenderer } from 'electron';
|
||||
|
||||
contextBridge.exposeInMainWorld('electron', {
|
||||
startWebSocket: (port: number) => ipcRenderer.send('start-websocket', port),
|
||||
stopWebSocket: () => ipcRenderer.send('stop-websocket'),
|
||||
openDevTools: () => ipcRenderer.send('open-devtools'),
|
||||
onWebSocketStatus: (callback: (message: string) => void) => ipcRenderer.on('websocket-status', (event, message) => callback(message)),
|
||||
onLogMessage: (callback: (message: string) => void) => ipcRenderer.on('log-message', (event, message) => callback(message)),
|
||||
env: {
|
||||
PORT: process.env.PORT || '8080' // 提供環境變數
|
||||
}
|
||||
});
|
||||
74
src/electron/renderer.ts
Normal file
74
src/electron/renderer.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
const maxLogs = 200; // 设置最大日志数量
|
||||
const logs: string[] = [];
|
||||
|
||||
|
||||
|
||||
// 格式化时间戳的函数
|
||||
function formatDate(date: Date): string {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
|
||||
// return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
|
||||
return `${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
function updateLogDisplay() {
|
||||
const logContainer = document.getElementById('log') as HTMLElement;
|
||||
if (logContainer) {
|
||||
logContainer.innerText = logs.join('\n');
|
||||
logContainer.scrollTop = 0; // 保持滚动位置在顶部
|
||||
}
|
||||
}
|
||||
|
||||
function addLog(message: string) {
|
||||
const timestamp = formatDate(new Date()); // 使用当前时间生成时间戳
|
||||
const logMessage = `[${timestamp}] ${message}`; // 在日志消息前添加时间戳
|
||||
|
||||
logs.unshift(logMessage); // 在数组开头插入新消息
|
||||
|
||||
// 如果日志超过200条,删除最旧的一条(数组末尾的元素)
|
||||
if (logs.length > maxLogs) {
|
||||
logs.pop();
|
||||
}
|
||||
|
||||
updateLogDisplay();
|
||||
}
|
||||
|
||||
// 设置默认端口值
|
||||
const portInputElement = document.getElementById('port') as HTMLInputElement;
|
||||
if (portInputElement) {
|
||||
const defaultPort = window.electron.env.PORT; // 从预加载脚本中获取默认端口
|
||||
portInputElement.value = defaultPort;
|
||||
}
|
||||
|
||||
document.getElementById('startBtn')?.addEventListener('click', () => {
|
||||
const portElement = document.getElementById('port') as HTMLInputElement;
|
||||
const port = parseInt(portElement.value, 10);
|
||||
window.electron.startWebSocket(port);
|
||||
});
|
||||
|
||||
document.getElementById('stopBtn')?.addEventListener('click', () => {
|
||||
window.electron.stopWebSocket();
|
||||
});
|
||||
|
||||
document.getElementById('devToolsBtn')?.addEventListener('click', () => {
|
||||
window.electron.openDevTools();
|
||||
});
|
||||
|
||||
window.electron.onWebSocketStatus((message: string) => {
|
||||
console.log(`WebSocket status: ${message}`);
|
||||
const statusElement = document.getElementById('status');
|
||||
if (statusElement) {
|
||||
statusElement.innerText = `Status: ${message}`;
|
||||
}
|
||||
addLog(message); // 將 WebSocket 狀態消息添加到日誌顯示區
|
||||
});
|
||||
|
||||
// 监听主进程发送的日志消息
|
||||
window.electron.onLogMessage((message: string) => {
|
||||
addLog(message); // 將日誌消息添加到顯示區
|
||||
});
|
||||
Reference in New Issue
Block a user