/** * 主窗口 */ import { ipcMain, BrowserWindow, type BrowserWindowConstructorOptions } from "electron" import * as remote from "@electron/remote/main" import GlobalConfig from "./GlobalConfig" import { mainLog } from "../utils/logger" import { spawn } from "child_process" class WinMain { /** 窗口实例 */ private static WIN_INST: BrowserWindow | null = null /** 窗口配置 */ private static WIN_CONFIG: BrowserWindowConstructorOptions = { icon: GlobalConfig.getAppLogo(), // 图标 title: GlobalConfig.getAppTitle(), // 如果由 loadURL() 加载的 HTML 文件中含有标签 ,此属性将被忽略 minWidth: 500, minHeight: 400, show: false, // 是否在创建时显示, 默认值为 true frame: true, // 设置为false来隐藏标题栏 center: true, // 是否在屏幕居中 hasShadow: false, // 窗口是否有阴影. 默认值为 true resizable: true, // 是否允许拉伸大小 fullscreenable: true, // 是否允许全屏,为 false 则插件 screenfull 不起作用 autoHideMenuBar: true, // 自动隐藏菜单栏, 除非按了 Alt 键, 默认值为 false backgroundColor: "#fff", // 背景颜色 webPreferences: { spellcheck: false, // 禁用拼写检查器 disableBlinkFeatures: "SourceMap", // 以 "," 分隔的禁用特性列表 devTools: true, // 是否开启 DevTools, 如果设置为 false(默认值为 true), 则无法使用 BrowserWindow.webContents.openDevTools() webSecurity: false, // 当设置为 false, 将禁用同源策略 nodeIntegration: true, // 是否启用 Node 集成 contextIsolation: false, // 是否在独立 JavaScript 环境中运行 Electron API 和指定的 preload 脚本,默认为 true backgroundThrottling: false, // 是否在页面成为背景时限制动画和计时器,默认值为 true nodeIntegrationInWorker: true // 是否在 Web 工作器中启用了 Node 集成 } } /** 获取窗口实例 */ static getWinInst() { return this.WIN_INST } /** 显示窗口 */ static show(key?: string, center?: boolean) { mainLog.log("[show main win] ", key) this.WIN_INST?.show() this.WIN_INST?.focus() center && this.WIN_INST?.center() } /** 创建窗口 */ static create() { if (this.WIN_INST) return this.WIN_INST = new BrowserWindow(this.WIN_CONFIG) this.WIN_INST.removeMenu() if (GlobalConfig.IS_DEV_MODE) { this.WIN_INST.loadURL(GlobalConfig.getWinUrl()) } else { this.WIN_INST.loadFile(GlobalConfig.getWinUrl()) } // 启用 remote remote.enable(this.WIN_INST.webContents) // 窗口-准备好显示 // 在窗口的控制台中使用 F5 刷新时,也会触发该事件 this.WIN_INST.on("ready-to-show", () => { this.show("win=>ready-to-show", true) GlobalConfig.IS_DEV_MODE && this.openDevTools() }) // 窗口-即将关闭 this.WIN_INST.on("close", () => {}) // 窗口-已关闭 this.WIN_INST.on("closed", () => (this.WIN_INST = null)) } /** 打开控制台 */ static openDevTools() { if (!this.WIN_INST) return const winCtns = this.WIN_INST.webContents if (winCtns.isDevToolsOpened()) return winCtns.openDevTools({ mode: "undocked", title: "tools" }) } /** 监听通信事件 */ static ipcListening() { // 中转消息-代替中央事件总线 ipcMain.on("vue_bus", (_, { channel, data }) => { if (!this.WIN_INST || !channel) return this.WIN_INST.webContents.send(channel, data) }) // 设置窗口最小值 ipcMain.on("set_min_size", (_, dto: WinStateDTO) => { if (!this.WIN_INST) return const size = GlobalConfig.adaptByScreen(dto, this.WIN_INST) const val = this.WIN_INST.isResizable() this.WIN_INST.setResizable(true) this.WIN_INST.setMinimumSize(size.width, size.height) this.WIN_INST.setSize(size.width, size.height) this.WIN_INST.setResizable(val) }) // 设置窗口大小 ipcMain.on("set_win_size", (_, dto: WinStateDTO) => { if (!this.WIN_INST) return const size = GlobalConfig.adaptByScreen(dto, this.WIN_INST) this.WIN_INST.setResizable(true) this.WIN_INST.setSize(size.width, size.height) dto.center && this.WIN_INST.center() this.WIN_INST.setMaximizable(dto.maxable) this.WIN_INST.setResizable(dto.resizable) }) // 获取项目地址 ipcMain.handle("project-address", () => { return process.cwd() }) ipcMain.handle("cmd-comm", (_, dir: string, comm: string) => { return new Promise((resolve, reject) => { const cmd = spawn("cmd", [dir, comm]) cmd.stdout.on("data", (data) => { resolve(`stdout: ${data}`) }) cmd.stderr.on("data", (data) => { reject(`stderr: ${data}`) }) cmd.on("close", (code) => { console.log(`child process exited with code ${code}`) }) }) }) } } export default WinMain