[add] 畫面調整
This commit is contained in:
parent
0271674764
commit
cad4bb3b56
28
package-lock.json
generated
28
package-lock.json
generated
@ -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",
|
||||||
|
@ -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
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>
|
@ -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 服务器
|
@ -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
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); // 將日誌消息添加到顯示區
|
||||||
|
});
|
2
src/global.d.ts
vendored
2
src/global.d.ts
vendored
@ -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; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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>
|
|
@ -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);
|
|
||||||
// });
|
|
Loading…
Reference in New Issue
Block a user