background.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. 'use strict'
  2. import { app, protocol, globalShortcut, BrowserWindow, ipcMain, Menu, dialog } from 'electron'
  3. import {
  4. createProtocol
  5. } from 'vue-cli-plugin-electron-builder/lib'
  6. import { autoUpdater } from 'electron-updater'
  7. const contextMenu = require('electron-context-menu')
  8. contextMenu({
  9. labels: {
  10. cut: '剪切',
  11. copy: '复制',
  12. paste: '粘贴',
  13. save: '保存',
  14. saveImageAs: '图片另存为'
  15. },
  16. prepend: () => [
  17. {
  18. type: 'separator'
  19. },
  20. {
  21. type: 'separator'
  22. },
  23. {
  24. label: 'Invisible',
  25. visible: false
  26. },
  27. {
  28. type: 'separator'
  29. },
  30. {
  31. type: 'separator'
  32. }
  33. ],
  34. append: () => {},
  35. showSearchWithGoogle: false,
  36. showCopyImageAddress: false,
  37. showSaveImageAs: true,
  38. showSaveImage: false,
  39. showCopyImage: false,
  40. showInspectElement: false
  41. })
  42. global.windows = {}
  43. const Store = require('electron-store')
  44. const localStore = new Store()
  45. localStore.delete('token')
  46. const log = require('electron-log')
  47. log.transports.file.level = 'silly'
  48. const isDevelopment = process.env.NODE_ENV !== 'production'
  49. const path = require('path')
  50. // Keep a global reference of the window object, if you don't, the window will
  51. // be closed automatically when the JavaScript object is garbage collected.
  52. let win
  53. let canQuit = false
  54. let workerWin
  55. // Scheme must be registered before the app is ready
  56. protocol.registerStandardSchemes(['app'], { secure: true })
  57. const { download } = require('electron-dl')
  58. function createWindow () {
  59. // Create the browser window.
  60. win = new BrowserWindow({
  61. width: 800,
  62. height: 600,
  63. show: false,
  64. icon: path.join(__static, process.env.VUE_APP_LOGO ? process.env.VUE_APP_LOGO + '.png' : 'icon.png'),
  65. webPreferences: { webSecurity: false, plugins: true }
  66. })
  67. global.windows.index = win.webContents.id
  68. win.maximize()
  69. win.show()
  70. log.info('当前软件版本号', app.getVersion())
  71. if (process.env.WEBPACK_DEV_SERVER_URL) {
  72. // Load the url of the dev server if in development mode
  73. win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
  74. if (!process.env.IS_TEST) win.webContents.openDevTools()
  75. } else {
  76. createProtocol('app')
  77. // Load the index.html when not in development
  78. win.loadURL('app://./index.html')
  79. }
  80. win.on('closed', () => {
  81. win = null
  82. workerWin && workerWin.close()
  83. })
  84. win.on('close', (e) => {
  85. if (canQuit) {
  86. app.quit()
  87. } else {
  88. e.preventDefault()
  89. dialog.showMessageBox({
  90. type: 'info',
  91. title: '提示',
  92. message: '确定退出软件吗?',
  93. buttons: ['是', '否']
  94. }, (index) => {
  95. if (index === 0) {
  96. canQuit = true
  97. app.quit()
  98. }
  99. })
  100. }
  101. })
  102. ipcMain.on('updateReady', (event, updateUrl) => {
  103. console.log('check update', updateUrl)
  104. checkForUpdates(updateUrl)
  105. })
  106. ipcMain.on('getPrinters', (event, updateUrl) => {
  107. win.webContents.send('sendPrinters', win.webContents.getPrinters())
  108. })
  109. ipcMain.on('open-directory-dialog', (event) => {
  110. dialog.showOpenDialog({
  111. properties: ['openDirectory'] // 'openFile', 'openDirectory'
  112. }, (files) => {
  113. if (files) event.sender.send('selected-directory', files)
  114. })
  115. })
  116. ipcMain.on('open-file-dialog', (event) => {
  117. dialog.showOpenDialog({
  118. properties: ['openFile'] // 'openFile', 'openDirectory'
  119. }, (files) => {
  120. if (files) event.sender.send('selected-file', files)
  121. })
  122. })
  123. ipcMain.on('download', async (event, args) => {
  124. log.info('下载', args)
  125. try {
  126. const file = await download(win, args, {
  127. saveAs: true,
  128. errorTitle: '下载出错'
  129. })
  130. event.sender.send('downloadSuccess', file)
  131. } catch (e) {
  132. console.log(JSON.stringify(e))
  133. event.sender.send('downloadError', e.message)
  134. }
  135. })
  136. globalShortcut.register('CommandOrControl+P', () => {
  137. localStore.openInEditor()
  138. })
  139. globalShortcut.register('F3', () => {
  140. BrowserWindow.getFocusedWindow().webContents.openDevTools()
  141. })
  142. }
  143. // 创建人脸识别弹框,放在主窗口识别预热,会导致页面卡顿
  144. function createWorker (devPath, prodPath) {
  145. // create hidden worker window
  146. workerWin = new BrowserWindow({
  147. show: true, // process.env.NODE_ENV !== 'production',
  148. alwaysOnTop: true,
  149. fullscreen: true, // process.env.NODE_ENV === 'production'
  150. webPreferences: { nodeIntegration: true, webSecurity: false }
  151. })
  152. workerWin.hide()
  153. global.windows.faceDetector = workerWin.webContents.id
  154. if (process.env.WEBPACK_DEV_SERVER_URL) {
  155. workerWin.loadURL(process.env.WEBPACK_DEV_SERVER_URL + devPath)
  156. } else {
  157. workerWin.loadURL(`app://./${prodPath}`)
  158. }
  159. workerWin.on('closed', () => { workerWin = null })
  160. }
  161. if (!isDevelopment) {
  162. // 单例应用,防止同时打开多个软件窗口
  163. const gotTheLock = app.requestSingleInstanceLock()
  164. if (!gotTheLock) {
  165. app.quit()
  166. } else {
  167. app.on('second-instance', (event, commandLine, workingDirectory) => {
  168. // Someone tried to run a second instance, we should focus our window.
  169. if (win) {
  170. if (win.isMinimized()) win.restore()
  171. win.focus()
  172. }
  173. })
  174. }
  175. }
  176. // Quit when all windows are closed.
  177. app.on('window-all-closed', () => {
  178. // On macOS it is common for applications and their menu bar
  179. // to stay active until the user quits explicitly with Cmd + Q
  180. if (process.platform !== 'darwin') {
  181. app.quit()
  182. }
  183. })
  184. app.on('activate', () => {
  185. // On macOS it's common to re-create a window in the app when the
  186. // dock icon is clicked and there are no other windows open.
  187. if (win === null) {
  188. createWindow()
  189. setMenu()
  190. }
  191. })
  192. // This method will be called when Electron has finished
  193. // initialization and is ready to create browser windows.
  194. // Some APIs can only be used after this event occurs.
  195. app.on('ready', async () => {
  196. if (isDevelopment && !process.env.IS_TEST) {
  197. // Install Vue Devtools
  198. try {
  199. // await installVueDevtools()
  200. } catch (e) {
  201. console.error('Vue Devtools failed to install:', e.toString())
  202. }
  203. }
  204. createWindow()
  205. setMenu()
  206. createWorker('worker', 'worker.html')
  207. })
  208. // Exit cleanly on request from parent process in development mode.
  209. if (isDevelopment) {
  210. if (process.platform === 'win32') {
  211. process.on('message', data => {
  212. if (data === 'graceful-exit') {
  213. app.quit()
  214. }
  215. })
  216. } else {
  217. process.on('SIGTERM', () => {
  218. app.quit()
  219. })
  220. }
  221. }
  222. const sendUpdateMessage = (message, data) => {
  223. log.warn(message)
  224. win.webContents.send('message', { message, data })
  225. }
  226. export function checkForUpdates (url) {
  227. if (process.env.NODE_ENV !== 'production') return
  228. // 设置自动更新
  229. autoUpdater.setFeedURL(url)
  230. autoUpdater.on('error', function (message) {
  231. sendUpdateMessage('error', message)
  232. })
  233. autoUpdater.on('checking-for-update', function (message) {
  234. sendUpdateMessage('checking-for-update', message)
  235. })
  236. autoUpdater.on('update-available', function (message) {
  237. sendUpdateMessage('update-available', message)
  238. })
  239. autoUpdater.on('update-not-available', function (message) {
  240. sendUpdateMessage('update-not-available', message)
  241. })
  242. // 更新下载进度事件
  243. autoUpdater.on('download-progress', function (progressObj) {
  244. sendUpdateMessage('downloadProgress', progressObj)
  245. })
  246. autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
  247. log.info(`已下载${event.version}`)
  248. var fs = require('fs-extra')
  249. var path = require('path')
  250. var fileName = event.downloadedFile
  251. var sourceFile = path.join(fileName)
  252. var destPath = path.join('C://售票软件', event.path)
  253. fs.copySync(sourceFile, destPath)
  254. log.info(`安装包移动完成`)
  255. ipcMain.on('updateNow', (e, arg) => {
  256. // some code here to handle event
  257. autoUpdater.quitAndInstall()
  258. })
  259. sendUpdateMessage('isUpdateNow')
  260. })
  261. // 执行自动更新检查
  262. autoUpdater.checkForUpdates().catch(e => {
  263. sendUpdateMessage('error', e)
  264. })
  265. // 取消退出软件后的自动更新
  266. autoUpdater.autoInstallOnAppQuit = false
  267. }
  268. export function setMenu () {
  269. // const version = app.getVersion()
  270. let template = [
  271. {
  272. label: '工具',
  273. submenu: [
  274. {
  275. label: '强制刷新',
  276. role: 'forcereload'
  277. },
  278. {
  279. label: '开发者工具',
  280. role: 'toggledevtools'
  281. }
  282. ]
  283. },
  284. {
  285. label: '配置',
  286. role: 'config',
  287. click: function () {
  288. win.webContents.send('goConfig')
  289. }
  290. },
  291. {
  292. label: '刷新',
  293. role: 'reload'
  294. }
  295. // {
  296. // label: '帮助',
  297. // submenu: [
  298. // {
  299. // label: `Version ${version}`,
  300. // enabled: false
  301. // },
  302. // {
  303. // label: '检查更新',
  304. // click: function () {
  305. // // require('electron').autoUpdater.quitAndInstall()
  306. // }
  307. // }
  308. // ]
  309. // }
  310. ]
  311. process.env.NODE_ENV === 'development' && (template.push(
  312. {
  313. label: 'Pos调试',
  314. click: function () {
  315. win.webContents.send('goPos')
  316. }
  317. }
  318. ))
  319. const menu = Menu.buildFromTemplate(template)
  320. Menu.setApplicationMenu(menu)
  321. }