const { app, BrowserWindow, Menu, ipcMain, globalShortcut, dialog, screen, Tray } = require('electron'); const { join } = require('path'); const { fork } = require('child_process'); const { platform } = require('process'); const mqtt = require('mqtt') const sleep = (ms) => new Promise(res => setTimeout(res, ms)); class MainSerivce { #mqttChannel = null #client = null #isMin = 1 constructor() { Menu.setApplicationMenu(null) // 去掉菜单栏 app.commandLine.appendSwitch('wm-window-animations-disabled') // 拖动闪屏 app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required'); this.loadingWin = null this.mainWin = null this.icon = join(__dirname, './icon/playGame.png') this.contrlEvent = null if (!app.requestSingleInstanceLock({ key: 'contrl' })) { app.quit() } else { app.on('ready', this.onRead.bind(this)) app.on('activate', (e, isVisible) => { if (!isVisible && this.mainWin) { // 兼容Mac dock 栏点击 this.mainWin.show() } }) app.on('window-all-closed', () => app.quit()) } } createLoading() { const { size: { width, height } } = screen.getPrimaryDisplay() this.loadingWin = new BrowserWindow({ frame: false, // 无边框(窗口、工具栏等),只包含网页内容 width, height, resizable: false, center: true, icon: this.icon, alwaysOnTop: true, transparent: true // 窗口是否支持透明,如果想做高级效果最好为true }) if (app.isPackaged) { this.loadingWin.loadFile(join(__dirname, './loading.html')) } else { this.loadingWin.loadFile('loading.html') } this.loadingWin.on('close', () => { this.loadingWin = null }) } createWindow() { this.mainWin = new BrowserWindow({ minWidth: 1300, minHeight: 760, width: 1300, height: 760, frame: false, transparent: true, icon: this.icon, webPreferences: { contextIsolation: true, nodeIntegration: true, webSecurity: false, // 去掉跨越 nodeIntegrationInWorker: true, preload: join(__dirname, './preload.js') }, show: false })// 创建一个窗口 // 不同环境加载不同文件 if (app.isPackaged) { this.mainWin.loadFile(join(__dirname, './index.html')) } else { this.mainWin.loadURL('http://localhost:6547/') } // 事件监听 this.mainWin.on('close', () => { this.mainWin = null }) } onRead() { this.createLoading() this.createWindow() // 图标 const tray = new Tray(this.icon) const contextMenu = Menu.buildFromTemplate([ { label: '退出', click: () => { this.mainWin.close() app.quit() } } ]) tray.setToolTip('控制端') tray.on('click', () => this.mainWin.show()) // 注册调试模式 globalShortcut.register('Ctrl+F12', () => { this.mainWin.webContents.toggleDevTools() }) // 最小化 globalShortcut.register('Ctrl+B', () => { if (this.#isMin & 1) { this.mainWin.hide() } else { this.mainWin.show() } this.#isMin++ }) // 系统环境 if (platform === 'win32') { // 右键 tray.setContextMenu(contextMenu) // 禁用右键 this.mainWin.hookWindowMessage(278, () => { this.mainWin.setEnabled(false);//窗口禁用 setTimeout(() => { this.mainWin.setEnabled(true); }, 100) //延时太快会立刻启动,太慢会妨碍窗口其他操作,可自行测试最佳时间 return true }) } else if (platform === 'darwin') { app.dock.setIcon(join(__dirname, './icon/playGame@2x.png')) } // 通信 ipcMain.on('signal', (_, evt, data) => { if (evt === 'close-loading') { if (this.loadingWin) this.loadingWin.close() this.mainWin.show() if (this.mainWin.isVisible()) this.connectLogi() } else if (evt === 'minWin') { this.mainWin.minimize() } else if (evt === 'closeWin') { this.#closeMqtt() this.mainWin.close() } else if (evt === 'maxWin') { if (data) { this.mainWin.maximize() } else { this.mainWin.setBounds({ width: 1300, height: 760 }) this.mainWin.center() } } else if (evt === 'loginMqtt') { this.#initMqtt(data) } else if (evt === 'closeMqtt') { this.mainWin.setBounds({ width: 1300, height: 760 }) this.mainWin.center() this.#closeMqtt() } else if (evt === 'sendMqtt') { try { const db = JSON.stringify(data) if (this.#client.connected && this.#mqttChannel) this.#client.publish(this.#mqttChannel, db) } catch (error) { console.log(error); } } }) } #initMqtt(data) { this.#closeMqtt() try { this.#client = mqtt.connect(data.url, { username: data.room, password: data.name }) // 监听 this.#client.on('connect', () => this.mainWin.webContents.send('message', { type: 'connect' })) this.#client.on('message', (_, msg, __) => { try { const db = JSON.parse(msg.toString()) if (db.type === 'join') this.#mqttChannel = db.channel this.mainWin.webContents.send('message', db) } catch (error) { console.log(error); } }) this.#client.on('error', (e) => { this.mainWin.webContents.send('message', { type: 'disconnect' }); this.#closeMqtt() }) } catch (error) { this.mainWin.webContents.send('message', { type: 'disconnect' }) } } #closeMqtt() { if (this.#client) this.#client.end() this.#client = null this.#mqttChannel = null this.#isMin = 1 } connectLogi() { this.contrlEvent = fork(join(__dirname, './logiControl.js')); this.contrlEvent.on('message', msg => { if (!msg || msg.type === 'err' || !msg.data || !msg.data[44]) { this.contrlEvent.disconnect() this.contrlEvent.kill(msg.pid ?? 'SIGKILL') this.contrlEvent = null dialog.showMessageBox(this.mainWin, { message: msg.text, type: 'error', title: '连接错误' }).then(async ({ response }) => { if (!response) { if (msg && msg.text.includes('请链接')) return await sleep(2000) this.connectLogi() } }) } else { if (this.mainWin && !this.mainWin.isDestroyed() && this.contrlEvent) this.mainWin?.webContents.send('message', { type: 'contrl', content: msg.data }) } }) } }; new MainSerivce()