WinMain.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /**
  2. * 主窗口
  3. */
  4. import { ipcMain, BrowserWindow, type BrowserWindowConstructorOptions } from "electron"
  5. import * as remote from "@electron/remote/main"
  6. import GlobalConfig from "./GlobalConfig"
  7. import { mainLog } from "../utils/logger"
  8. import { spawn } from "child_process"
  9. class WinMain {
  10. /** 窗口实例 */
  11. private static WIN_INST: BrowserWindow | null = null
  12. /** 窗口配置 */
  13. private static WIN_CONFIG: BrowserWindowConstructorOptions = {
  14. icon: GlobalConfig.getAppLogo(), // 图标
  15. title: GlobalConfig.getAppTitle(), // 如果由 loadURL() 加载的 HTML 文件中含有标签 <title>,此属性将被忽略
  16. minWidth: 500,
  17. minHeight: 400,
  18. show: false, // 是否在创建时显示, 默认值为 true
  19. frame: true, // 设置为false来隐藏标题栏
  20. center: true, // 是否在屏幕居中
  21. hasShadow: false, // 窗口是否有阴影. 默认值为 true
  22. resizable: true, // 是否允许拉伸大小
  23. fullscreenable: true, // 是否允许全屏,为 false 则插件 screenfull 不起作用
  24. autoHideMenuBar: true, // 自动隐藏菜单栏, 除非按了 Alt 键, 默认值为 false
  25. backgroundColor: "#fff", // 背景颜色
  26. webPreferences: {
  27. spellcheck: false, // 禁用拼写检查器
  28. disableBlinkFeatures: "SourceMap", // 以 "," 分隔的禁用特性列表
  29. devTools: true, // 是否开启 DevTools, 如果设置为 false(默认值为 true), 则无法使用 BrowserWindow.webContents.openDevTools()
  30. webSecurity: false, // 当设置为 false, 将禁用同源策略
  31. nodeIntegration: true, // 是否启用 Node 集成
  32. contextIsolation: false, // 是否在独立 JavaScript 环境中运行 Electron API 和指定的 preload 脚本,默认为 true
  33. backgroundThrottling: false, // 是否在页面成为背景时限制动画和计时器,默认值为 true
  34. nodeIntegrationInWorker: true // 是否在 Web 工作器中启用了 Node 集成
  35. }
  36. }
  37. /** 获取窗口实例 */
  38. static getWinInst() {
  39. return this.WIN_INST
  40. }
  41. /** 显示窗口 */
  42. static show(key?: string, center?: boolean) {
  43. mainLog.log("[show main win] ", key)
  44. this.WIN_INST?.show()
  45. this.WIN_INST?.focus()
  46. center && this.WIN_INST?.center()
  47. }
  48. /** 创建窗口 */
  49. static create() {
  50. if (this.WIN_INST) return
  51. this.WIN_INST = new BrowserWindow(this.WIN_CONFIG)
  52. this.WIN_INST.removeMenu()
  53. if (GlobalConfig.IS_DEV_MODE) {
  54. this.WIN_INST.loadURL(GlobalConfig.getWinUrl())
  55. } else {
  56. this.WIN_INST.loadFile(GlobalConfig.getWinUrl())
  57. }
  58. // 启用 remote
  59. remote.enable(this.WIN_INST.webContents)
  60. // 窗口-准备好显示
  61. // 在窗口的控制台中使用 F5 刷新时,也会触发该事件
  62. this.WIN_INST.on("ready-to-show", () => {
  63. this.show("win=>ready-to-show", true)
  64. GlobalConfig.IS_DEV_MODE && this.openDevTools()
  65. })
  66. // 窗口-即将关闭
  67. this.WIN_INST.on("close", () => {})
  68. // 窗口-已关闭
  69. this.WIN_INST.on("closed", () => (this.WIN_INST = null))
  70. }
  71. /** 打开控制台 */
  72. static openDevTools() {
  73. if (!this.WIN_INST) return
  74. const winCtns = this.WIN_INST.webContents
  75. if (winCtns.isDevToolsOpened()) return
  76. winCtns.openDevTools({ mode: "undocked", title: "tools" })
  77. }
  78. /** 监听通信事件 */
  79. static ipcListening() {
  80. // 中转消息-代替中央事件总线
  81. ipcMain.on("vue_bus", (_, { channel, data }) => {
  82. if (!this.WIN_INST || !channel) return
  83. this.WIN_INST.webContents.send(channel, data)
  84. })
  85. // 设置窗口最小值
  86. ipcMain.on("set_min_size", (_, dto: WinStateDTO) => {
  87. if (!this.WIN_INST) return
  88. const size = GlobalConfig.adaptByScreen(dto, this.WIN_INST)
  89. const val = this.WIN_INST.isResizable()
  90. this.WIN_INST.setResizable(true)
  91. this.WIN_INST.setMinimumSize(size.width, size.height)
  92. this.WIN_INST.setSize(size.width, size.height)
  93. this.WIN_INST.setResizable(val)
  94. })
  95. // 设置窗口大小
  96. ipcMain.on("set_win_size", (_, dto: WinStateDTO) => {
  97. if (!this.WIN_INST) return
  98. const size = GlobalConfig.adaptByScreen(dto, this.WIN_INST)
  99. this.WIN_INST.setResizable(true)
  100. this.WIN_INST.setSize(size.width, size.height)
  101. dto.center && this.WIN_INST.center()
  102. this.WIN_INST.setMaximizable(dto.maxable)
  103. this.WIN_INST.setResizable(dto.resizable)
  104. })
  105. // 获取项目地址
  106. ipcMain.handle("project-address", () => {
  107. return process.cwd()
  108. })
  109. ipcMain.handle("cmd-comm", (_, dir: string, comm: string) => {
  110. return new Promise((resolve, reject) => {
  111. const cmd = spawn("cmd", [dir, comm])
  112. cmd.stdout.on("data", (data) => {
  113. resolve(`stdout: ${data}`)
  114. })
  115. cmd.stderr.on("data", (data) => {
  116. reject(`stderr: ${data}`)
  117. })
  118. cmd.on("close", (code) => {
  119. console.log(`child process exited with code ${code}`)
  120. })
  121. })
  122. })
  123. }
  124. }
  125. export default WinMain