[add] 畫面調整

This commit is contained in:
建喵 2024-08-25 22:34:21 +08:00
parent 0271674764
commit cad4bb3b56
12 changed files with 204 additions and 99 deletions

1
.env Normal file
View File

@ -0,0 +1 @@
PORT=9005

28
package-lock.json generated
View File

@ -9,6 +9,8 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"dayjs": "^1.11.13",
"dotenv": "^16.4.5",
"ws": "^8.18.0" "ws": "^8.18.0"
}, },
"bin": { "bin": {
@ -1885,6 +1887,11 @@
"node": ">= 10" "node": ">= 10"
} }
}, },
"node_modules/dayjs": {
"version": "1.11.13",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.6", "version": "4.3.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
@ -2088,12 +2095,14 @@
} }
}, },
"node_modules/dotenv": { "node_modules/dotenv": {
"version": "9.0.2", "version": "16.4.5",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
"integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
"dev": true,
"engines": { "engines": {
"node": ">=10" "node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
} }
}, },
"node_modules/dotenv-expand": { "node_modules/dotenv-expand": {
@ -4109,6 +4118,15 @@
"node": ">=12.0.0" "node": ">=12.0.0"
} }
}, },
"node_modules/read-config-file/node_modules/dotenv": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz",
"integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/read-pkg": { "node_modules/read-pkg": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",

View File

@ -1,10 +1,10 @@
{ {
"name": "sdserver", "name": "sdserver",
"version": "1.0.0", "version": "1.0.0",
"main": "dist/main.js", "main": "dist/electron/main.js",
"scripts": { "scripts": {
"start": "electron .", "start": "electron .",
"build": "tsc && copyfiles -u 1 src/index.html dist/", "build": "tsc && copyfiles -u 1 src/electron/index.html dist/ && copyfiles -u 1 src/electron/index.css dist/",
"pack": "electron-packager . SDServer --platform=win32 --arch=x64 --out=dist/", "pack": "electron-packager . SDServer --platform=win32 --arch=x64 --out=dist/",
"buildexe": "npx electron-builder", "buildexe": "npx electron-builder",
"watch": "nodemon" "watch": "nodemon"
@ -21,6 +21,8 @@
} }
}, },
"dependencies": { "dependencies": {
"dayjs": "^1.11.13",
"dotenv": "^16.4.5",
"ws": "^8.18.0" "ws": "^8.18.0"
}, },
"devDependencies": { "devDependencies": {

38
src/electron/index.css Normal file
View 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
View 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>

View File

@ -1,10 +1,14 @@
// src/main.ts // src/main.ts
import dotenv from 'dotenv';
import { app, BrowserWindow, ipcMain } from 'electron'; import { app, BrowserWindow, ipcMain } from 'electron';
import * as path from 'path'; import * as path from 'path';
import { WebSocketServer } from 'ws'; import { WebSocketServer } from 'ws';
// Load environment variables from .env file
dotenv.config();
let server: WebSocketServer | null = null; let server: WebSocketServer | null = null;
let port = 8080; // 默认端口 let port: number = process.env.PORT ? parseInt(process.env.PORT, 10) : 8080; // 默认端口为 8080
function createWindow() { function createWindow() {
const win = new BrowserWindow({ const win = new BrowserWindow({
@ -20,13 +24,28 @@ function createWindow() {
}); });
win.loadFile(path.join(__dirname, 'index.html')); win.loadFile(path.join(__dirname, 'index.html'));
win.webContents.openDevTools(); // win.webContents.openDevTools();
return win; return win;
} }
let mainWindow: BrowserWindow | null = null; 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(() => { app.whenReady().then(() => {
mainWindow = createWindow(); mainWindow = createWindow();
@ -53,13 +72,15 @@ ipcMain.on('start-websocket', (event, portNumber: number) => {
server = new WebSocketServer({ port: port }); server = new WebSocketServer({ port: port });
server.on('connection', (socket) => { server.on('connection', (socket, request) => {
console.log(`WebSocket server started on port ${port}`); const ip = request.socket.remoteAddress.replace("::ffff:", "") || 'Unknown IP';
console.log(`Client connected from IP: ${ip}`);
socket.send('Welcome to the WebSocket server'); socket.send('Welcome to the WebSocket server');
socket.on('message', (message: string) => { socket.on('message', (message: string) => {
console.log(`Received message: ${message}`); console.log(`[RPC] 收到client呼叫: ${message}`);
socket.send(`Server received your message: ${message}`); socket.send(`Server received your message: ${message}`);
console.log(`[RPC] 回傳client呼叫: ${message}`);
}); });
socket.on('close', () => { socket.on('close', () => {
@ -67,7 +88,7 @@ ipcMain.on('start-websocket', (event, portNumber: number) => {
}); });
}); });
event.reply('websocket-status', `WebSocket server started on port ${port} 88`); event.reply('websocket-status', `WebSocket server started on port ${port}`);
}); });
// 关闭 WebSocket 服务器 // 关闭 WebSocket 服务器

View File

@ -5,5 +5,9 @@ contextBridge.exposeInMainWorld('electron', {
startWebSocket: (port: number) => ipcRenderer.send('start-websocket', port), startWebSocket: (port: number) => ipcRenderer.send('start-websocket', port),
stopWebSocket: () => ipcRenderer.send('stop-websocket'), stopWebSocket: () => ipcRenderer.send('stop-websocket'),
openDevTools: () => ipcRenderer.send('open-devtools'), openDevTools: () => ipcRenderer.send('open-devtools'),
onWebSocketStatus: (callback: (message: string) => void) => ipcRenderer.on('websocket-status', (event, message) => callback(message)) 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
View 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); // 將日誌消息添加到顯示區
});

2
src/global.d.ts vendored
View File

@ -5,5 +5,7 @@ interface Window {
stopWebSocket: () => void; stopWebSocket: () => void;
openDevTools: () => void; openDevTools: () => void;
onWebSocketStatus: (callback: (message: string) => void) => void; onWebSocketStatus: (callback: (message: string) => void) => void;
onLogMessage: (callback: (message: string) => void) => void; // 添加這行以處理日誌消息
env: { PORT: string; };
}; };
} }

View File

@ -1,33 +0,0 @@
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<title>WebSocket Control</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
button {
margin: 5px;
}
</style>
</head>
<body>
<h1>SD Server Control</h1>
<label for="port">Port:</label>
<input type="number" id="port" value="8080">
<button id="startBtn">Start WebSocket Server</button>
<button id="stopBtn">Stop WebSocket Server</button>
<button id="devToolsBtn">Open DevTools</button>
<p id="status">Status: Waiting for actions...</p>
<script src="renderer.js"></script>
</body>
</html>

View File

@ -1,51 +0,0 @@
document.getElementById('startBtn')?.addEventListener('click', () => {
// console.log('Start WebSocket button clicked');
const portElement = document.getElementById('port') as HTMLInputElement;
const port = parseInt(portElement.value, 10);
window.electron.startWebSocket(port);
});
document.getElementById('stopBtn')?.addEventListener('click', () => {
// console.log('Stop WebSocket button clicked');
window.electron.stopWebSocket();
});
document.getElementById('devToolsBtn')?.addEventListener('click', () => {
// console.log('Open DevTools button clicked');
window.electron.openDevTools();
});
window.electron.onWebSocketStatus((message: string) => {
console.log(`WebSocket status: ${message}`);
const statusElement = document.getElementById('status');
if (statusElement) {
statusElement.innerText = `Status: ${message}`;
}
});
// document.getElementById('startBtn')?.addEventListener('click', () => {
// // console.log('Start WebSocket button clicked');
// const portElement = document.getElementById('port') as HTMLInputElement;
// const port = parseInt(portElement.value, 10);
// ipcRenderer.send('start-websocket', port);
// });
// document.getElementById('stopBtn')?.addEventListener('click', () => {
// // console.log('Stop WebSocket button clicked');
// ipcRenderer.send('stop-websocket');
// });
// document.getElementById('devToolsBtn')?.addEventListener('click', () => {
// // console.log('Open DevTools button clicked');
// ipcRenderer.send('open-devtools');
// });
// function onWebSocketStatus(callback: (message: string) => void) {
// ipcRenderer.on('websocket-status', (event, message) => callback(message));
// }
// // 監聽 WebSocket 狀態
// onWebSocketStatus((message) => {
// console.log('WebSocket status:', message);
// });