-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.ts
220 lines (193 loc) · 7.14 KB
/
app.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/*
* @Description: 主进程(主窗口创建,不含子窗口)
* @Autor: HuiSir<[email protected]>
* @Date: 2021-05-22 23:45:01
* @LastEditTime: 2021-12-03 23:46:58
*/
import { app, BrowserWindow, Menu, ipcMain } from 'electron'
import path from 'path'
import router from "./sys/router"
import { dataPool, cachePool } from "./sys/tools/DBPool"
import { Print } from './sys/tools/Logger' //日志
import CONST from './sys/config/const'
import request from 'request'
import { obj2Query } from './sys/tools/utils'
import curWin from './sys/tools/curWin'
import Options from './sys/service/Options'
import { operate } from './sys/service/operationLog'
// 环境变量
const IsDev: boolean = process.env.NODE_ENV === "development"
/**
* 窗口集合
* 整个软件包含两个窗口,一个为登录窗口,一个为主窗口
*/
const WINS: Set<any> = new Set()
// 当前主窗口是否为登陆窗口
let LoginWin = false
// 创建一个带有预加载脚本的新的浏览器窗口
function createWindow(isLoginWin = false, query?: object, callback?: () => void): BrowserWindow {
//隐藏菜单栏
Menu.setApplicationMenu(null)
LoginWin = isLoginWin
let {
MAIN_WIN_WIDTH: winWidth,
MAIN_WIN_HEIGHT: winHeight,
MAIN_WIN_BG_COLOR: winBgColor
} = CONST
// 如果当前没有窗口,默认打开的是登录窗口
if (WINS.size === 0 || isLoginWin) {
winWidth = CONST.LOGIN_WIN_WIDTH
winHeight = CONST.LOGIN_WIN_HEIGHT
winBgColor = CONST.LOGIN_WIN_BG_COLOR
}
// 创建了一个新的窗口
let Win: any = new BrowserWindow({
show: false, // 默认先隐藏,等待渲染进程完全启动后再显示窗口,可避免窗口闪烁
fullscreen: false, // 是否全屏
title: '加载中...', // 窗口标题
width: winWidth,
height: winHeight,
backgroundColor: winBgColor, // 初始化背景
resizable: IsDev, // 宽高拖拽
frame: IsDev, // 边框显示
transparent: !IsDev, // 窗口透明
icon: path.join(__dirname, 'favicon.ico'),
webPreferences: {// web首选项
// 是否开启Node集成, 并且可以使用像 require 和 process 这样的node APIs 去访问低层系统资源,
// Electron v5之后的默认为false
nodeIntegration: false,
webSecurity: false, // 关闭窗口跨域,可访问本地绝对路径资源(图片)
contextIsolation: true, // 上下文隔离(主进程和渲染进程隔离)防止原型污染
enableRemoteModule: true, // 允许渲染进程中使用远程(remote)模块访问窗口方法
// 预加载脚本。充当Node.js 和您的网页之间的桥梁。
// 它允许将特定的 API 和行为暴露到你的网页上,而不是危险地把整个 Node.js 的 API暴露。
preload: path.join(__dirname, 'sys/preload/index.js')
}
})
// 缓存窗口对象
curWin.set(Win)
if (IsDev) {
// 获取端口号
const Port = process.env['npm_package_config_port']
// 由于vue-cli-service serve和electron命令同时启动,无法判定哪个先启动完成
// 所以这里写个定时器,不断加载直到加载成功
let reqFlag = false
const Timer = setInterval(() => {
request("http://127.0.0.1:" + Port, function (err: any) {
if (!err && !reqFlag) {
reqFlag = true
const sto = setTimeout(() => {
Print.info("正在启动窗口,请等待...")
clearTimeout(sto)
}, 500)
// 打开测试页
Win.loadURL(`http://127.0.0.1:${Port}${query ? '?' + obj2Query(query) : ''}#${WINS.size === 0 || isLoginWin ? 'login' : 'home'}`)
// 开启调试.
Win.webContents.openDevTools()
clearInterval(Timer)
}
})
}, 500)
} else {
// 入口页面
Win.loadURL(path.join(__dirname, `index.html${query ? '?' + obj2Query(query) : ''}#${WINS.size === 0 || isLoginWin ? 'login' : 'home'}`))
}
// 将窗口push到集合中
WINS.add(Win)
// 渲染进程ready后再显示窗口
Win.once('ready-to-show', () => {
// 这里判断,如果是窗口启动完成,则关闭先前窗口
WINS.forEach((item) => {
if (item !== Win) {
item.close()
}
})
// 显示窗口
Win.show()
// 打印日志
Print.info("窗口启动成功")
// 启动回调
callback && callback()
})
//从已关闭的窗口Set中移除引用
Win.on('closed', () => {
WINS.delete(Win)
Win = null
})
return Win
}
// 监听Electron执行打包完成
app.whenReady().then(async () => {
if (IsDev) {
// 安装vue-devtools插件
// 使用try catch避免阻塞后续脚本执行
try {
const installExtension = require('electron-devtools-installer-bycrx')
const res = await installExtension({
id: path.basename(CONST.VUE_DEVTOOLS_CDN_LINK).split(".")[0],
path: CONST.VUE_DEVTOOLS_CDN_LINK,
})
if (res) {
Print.info("插件加载成功:" + res)
}
} catch (err) {
Print.info('Vue Devtools 加载失败:', err)
}
}
// 打开登录窗口
createWindow(true)
// 引用程序激活监听器
app.on('activate', () => {
// 激活后没有可见窗口(BrowserWindow.getAllWindows())时,才能创建新的浏览器窗口。
// 例如,在首次启动应用程序后或重启运行中的应用程序。
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
/**
* 自动备份
*/
const autoBackup = (callback: () => void) => {
// 判断当前窗口,若为登陆窗口,则无需备份
if (LoginWin) {
callback()
return
}
// 查询是否需要自动备份
Options.getOptionsData().then((res) => {
if (res && res.ok && res.data.auto_backup) {
// 执行备份
Options.doBackup().then(() => {
callback()
}).catch(() => {
callback()
})
} else {
callback()
}
}).catch(() => {
callback()
})
}
/**
* 退出所有窗口时 关闭主进程、关闭数据库连接
* 由于有两个窗口,所以要保证两个窗口不能同时关闭
* 所以若登录成功后不能立即关闭登录窗口,需要等待主窗口打开后再关闭
*/
app.on('window-all-closed', () => {
operate("退出程序")
// 当应用程序不再有任何打开窗口时试图退出
if (process.platform !== 'darwin') {
// 备份
autoBackup(() => {
// 关闭数据库连接
dataPool.closeAll()
cachePool.closeAll()
// 关闭主进程
app.exit(0)
})
}
})
// 系统操作分发
router(ipcMain, createWindow)