331 lines
9.8 KiB
JavaScript
331 lines
9.8 KiB
JavaScript
|
import { app, shell, BrowserWindow, ipcMain, session, BrowserView } from 'electron'
|
|||
|
import { join } from 'path'
|
|||
|
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
|
|||
|
import icon from '../../resources/icon.png?asset'
|
|||
|
import File from './file'
|
|||
|
import Logger from './logger' // 日志封装
|
|||
|
import chat from './chat' // chat封装
|
|||
|
import Store from './store' // Store封装
|
|||
|
import updateInit from './update'
|
|||
|
// 代理 electron/remote
|
|||
|
// 第一步:引入remote
|
|||
|
import remote from '@electron/remote/main'
|
|||
|
// 第二步: 初始化remote
|
|||
|
remote.initialize()
|
|||
|
// 日志配置-初始化(日志直接绑定到console上)
|
|||
|
if(!is.dev) Logger.initialize()
|
|||
|
// 持久化数据-初始化
|
|||
|
Store.initialize()
|
|||
|
|
|||
|
File({ app, shell, BrowserWindow, ipcMain })
|
|||
|
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
|
|||
|
let mainWindow, loginWindow
|
|||
|
|
|||
|
const additionalData = {myKey:'ys_axi_smarttalk'}
|
|||
|
const gotTheLock = app.requestSingleInstanceLock(additionalData)
|
|||
|
|
|||
|
if(!gotTheLock){
|
|||
|
app.quit()
|
|||
|
}else{
|
|||
|
app.on('second-instance',(event,commandLine,workingDirectory,additionalData)=>{
|
|||
|
//输入从第二个实例中接收到的数据
|
|||
|
console.log(additionalData)
|
|||
|
//有人试图运行第二个实例,我们应该关注我们的窗口
|
|||
|
if(mainWindow){
|
|||
|
if(mainWindow.isMinimized()) mainWindow.restore()
|
|||
|
mainWindow.focus()
|
|||
|
}
|
|||
|
if(loginWindow){
|
|||
|
if(loginWindow.isMinimized()) loginWindow.restore()
|
|||
|
loginWindow.focus()
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
//登录窗口
|
|||
|
function createLoginWindow() {
|
|||
|
if (loginWindow) return
|
|||
|
loginWindow = new BrowserWindow({
|
|||
|
width: 888,
|
|||
|
height: 520,
|
|||
|
show: false,
|
|||
|
frame: false,
|
|||
|
autoHideMenuBar: true,
|
|||
|
maximizable: false,
|
|||
|
resizable: false,
|
|||
|
icon: join(__dirname, '../../resources/logo2.ico'),
|
|||
|
...(process.platform === 'linux' ? { icon } : {}),
|
|||
|
webPreferences: {
|
|||
|
defaultEncoding: 'utf-8',
|
|||
|
preload: join(__dirname, '../preload/index.js'),
|
|||
|
sandbox: false,
|
|||
|
nodeIntegration: true,
|
|||
|
contextIsolation: false // 沙箱取消
|
|||
|
}
|
|||
|
})
|
|||
|
loginWindow.type = 'login' // 唯一标识
|
|||
|
// handleUpdate(loginWindow,ipcMain)
|
|||
|
// const loginURL = is.dev ? `http://localhost:5173/#/login` : `file://${__dirname}/index.html/#/login`
|
|||
|
// loginWindow.loadURL(loginURL)
|
|||
|
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
|
|||
|
loginWindow.loadURL('http://localhost:5173/#/login')
|
|||
|
} else {
|
|||
|
loginWindow.loadFile(join(__dirname, '../renderer/index.html'), { hash: 'login' })
|
|||
|
updateInit(loginWindow)
|
|||
|
}
|
|||
|
if (import.meta.env.VITE_SHOW_DEV_TOOLS === 'true') loginWindow.webContents.openDevTools()
|
|||
|
loginWindow.once('ready-to-show', () => {
|
|||
|
loginWindow.show()
|
|||
|
})
|
|||
|
|
|||
|
loginWindow.on('closed', () => {
|
|||
|
loginWindow = null
|
|||
|
})
|
|||
|
|
|||
|
remote.enable(loginWindow.webContents)
|
|||
|
}
|
|||
|
//主窗口
|
|||
|
function createMainWindow() {
|
|||
|
mainWindow = new BrowserWindow({
|
|||
|
width: 1350,
|
|||
|
minWidth: 1200,
|
|||
|
height: 700,
|
|||
|
minHeight: 700,
|
|||
|
show: false,
|
|||
|
frame: false, // 无边框
|
|||
|
autoHideMenuBar: true,
|
|||
|
maximizable: false,
|
|||
|
icon: join(__dirname, '../../resources/logo2.ico'),
|
|||
|
...(process.platform === 'linux' ? { icon } : {}),
|
|||
|
webPreferences: {
|
|||
|
defaultEncoding: 'utf-8',
|
|||
|
preload: join(__dirname, '../preload/index.js'),
|
|||
|
sandbox: false,
|
|||
|
// nodeIntegration: true,
|
|||
|
nodeIntegration: true, // nodeApi调用
|
|||
|
contextIsolation: false // 沙箱取消
|
|||
|
// webSecurity: false // 跨域关闭
|
|||
|
}
|
|||
|
})
|
|||
|
mainWindow.type = 'main' // 唯一标识
|
|||
|
mainWindow.on('ready-to-show', () => {
|
|||
|
mainWindow.show()
|
|||
|
})
|
|||
|
mainWindow.on('closed', () => {
|
|||
|
setTimeout(() => {
|
|||
|
// 延迟销毁
|
|||
|
mainWindow = null
|
|||
|
}, 1000)
|
|||
|
// app.quit() // 主窗口关闭-结束所有进程
|
|||
|
})
|
|||
|
mainWindow.on('resize', () => {
|
|||
|
const { width, height } = mainWindow.getBounds();
|
|||
|
mainWindow.webContents.send('minWinResize', { width, height });
|
|||
|
});
|
|||
|
|
|||
|
mainWindow.webContents.setWindowOpenHandler((details) => {
|
|||
|
shell.openExternal(details.url)
|
|||
|
return { action: 'deny' }
|
|||
|
})
|
|||
|
if (import.meta.env.VITE_SHOW_DEV_TOOLS === 'true') mainWindow.webContents.openDevTools()
|
|||
|
|
|||
|
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
|
|||
|
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
|
|||
|
} else {
|
|||
|
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
|
|||
|
}
|
|||
|
|
|||
|
// mainWindow.setAlwaysOnTop(true, "screen-saver") // 将窗口设置为顶层窗口
|
|||
|
// mainWindow.setVisibleOnAllWorkspaces(true) // 如果窗口在所有工作区都可见
|
|||
|
mainWindow.maximize();
|
|||
|
// 第三步: 开启remote服务
|
|||
|
remote.enable(mainWindow.webContents)
|
|||
|
}
|
|||
|
|
|||
|
// 打开外部链接窗口
|
|||
|
let linkWin = {}
|
|||
|
async function createLinkWin(data) {
|
|||
|
if (linkWin[data.key]) return
|
|||
|
|
|||
|
linkWin[data.key] = new BrowserWindow({
|
|||
|
show: false,
|
|||
|
frame: true,
|
|||
|
maximizable: true,
|
|||
|
autoHideMenuBar: true,
|
|||
|
...(process.platform === 'linux' ? { icon } : {}),
|
|||
|
webPreferences: {
|
|||
|
defaultEncoding: 'utf-8',
|
|||
|
sandbox: false,
|
|||
|
nodeIntegration: true,
|
|||
|
worldSafeExecuteJavaScript: true,
|
|||
|
contextIsolation: true
|
|||
|
}
|
|||
|
})
|
|||
|
linkWin[data.key].type = 'link'+data.key // 唯一标识
|
|||
|
|
|||
|
let cookieDetails = { ...data.cookieData }
|
|||
|
await linkWin[data.key].webContents.session.cookies
|
|||
|
.set(cookieDetails)
|
|||
|
.then(() => {})
|
|||
|
.catch((error) => {})
|
|||
|
data.fullPath = data.fullPath.replaceAll('//', '/')
|
|||
|
if (data.fullPath.indexOf('?') !== -1) {
|
|||
|
data.fullPath += '&urlSource=smarttalk&t' + Date.now()
|
|||
|
}else {
|
|||
|
data.fullPath += '?urlSource=smarttalk&t' + Date.now()
|
|||
|
}
|
|||
|
linkWin[data.key].loadURL(data.fullPath)
|
|||
|
|
|||
|
linkWin[data.key].once('ready-to-show', () => {
|
|||
|
linkWin[data.key].show()
|
|||
|
linkWin[data.key].maximize()
|
|||
|
})
|
|||
|
linkWin[data.key].on('closed', () => {
|
|||
|
linkWin[data.key] = null
|
|||
|
delete linkWin[data.key]
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
// 初始化完成
|
|||
|
app.on('ready', () => {
|
|||
|
appWatchError() // 监听app错误
|
|||
|
process.env.LANG = 'en_US.UTF-8'
|
|||
|
// 设置应用程序用户模型标识符
|
|||
|
electronApp.setAppUserModelId('com.electron')
|
|||
|
|
|||
|
//一个新的browserWindow 被创建时触发
|
|||
|
app.on('browser-window-created', (_, window) => {
|
|||
|
optimizer.watchWindowShortcuts(window)
|
|||
|
})
|
|||
|
|
|||
|
//窗口 最大、最小、关闭
|
|||
|
ipcMain.on('minimize-window', () => {
|
|||
|
if (loginWindow) {
|
|||
|
loginWindow.minimize()
|
|||
|
}
|
|||
|
if (mainWindow) {
|
|||
|
mainWindow.minimize()
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
ipcMain.on('maximize-window', () => {
|
|||
|
mainWindow.isMaximized() ? mainWindow.unmaximize() : mainWindow.maximize()
|
|||
|
})
|
|||
|
|
|||
|
ipcMain.on('close-window', () => {
|
|||
|
if (loginWindow) {
|
|||
|
loginWindow.destroy()
|
|||
|
}
|
|||
|
if (mainWindow) {
|
|||
|
mainWindow.close() // 先发出这个关闭指令
|
|||
|
setTimeout(() => {
|
|||
|
//
|
|||
|
mainWindow.destroy()
|
|||
|
}, 200)
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
// 打开主窗口
|
|||
|
ipcMain.on('openMainWindow', () => {
|
|||
|
if (!mainWindow) {
|
|||
|
createMainWindow()
|
|||
|
}
|
|||
|
loginWindow.destroy()
|
|||
|
loginWindow = null
|
|||
|
})
|
|||
|
// 打开登录窗口
|
|||
|
ipcMain.on('openLoginWindow', () => {
|
|||
|
if (!loginWindow) {
|
|||
|
createLoginWindow()
|
|||
|
}
|
|||
|
mainWindow.destroy()
|
|||
|
mainWindow = null
|
|||
|
loginWindow.show()
|
|||
|
loginWindow.focus()
|
|||
|
})
|
|||
|
|
|||
|
//打开作业窗口
|
|||
|
ipcMain.on('openWindow', (e, data) => {
|
|||
|
createLinkWin(data)
|
|||
|
})
|
|||
|
// zdg: 消息监听
|
|||
|
handleAll()
|
|||
|
// 打开-登录窗口
|
|||
|
createLoginWindow()
|
|||
|
|
|||
|
app.on('activate', function () {
|
|||
|
if (BrowserWindow.getAllWindows().length === 0) createLoginWindow()
|
|||
|
})
|
|||
|
})
|
|||
|
|
|||
|
// Quit when all windows are closed, except on macOS. There, it's common
|
|||
|
// for applications and their menu bar to stay active until the user quits
|
|||
|
// explicitly with Cmd + Q.
|
|||
|
app.on('window-all-closed', () => {
|
|||
|
if (process.platform !== 'darwin') {
|
|||
|
app.quit()
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
// 监听全局事件
|
|||
|
function handleAll() {
|
|||
|
const chatInstance = chat.initialize() // im-chat 实例
|
|||
|
// 新窗口创建-监听
|
|||
|
ipcMain.handle('new-window', (e, data) => {
|
|||
|
const { id, type } = data
|
|||
|
const win = BrowserWindow.fromId(id)
|
|||
|
win.type = type // 绑定独立标识
|
|||
|
remote.enable(win.webContents) // 开启远程服务
|
|||
|
chatInstance.enable(win.webContents) // 开启im-chat
|
|||
|
console.log(`主进程 [${type}]: 窗口注册-远程代理-完毕(${Date.now()})`)
|
|||
|
})
|
|||
|
// 用于监听-状态管理变化-同步所有窗口
|
|||
|
ipcMain.handle('pinia-state-change', (e, storeName, jsonStr) => {
|
|||
|
|
|||
|
for(const curWin of BrowserWindow.getAllWindows()){
|
|||
|
const id = curWin.webContents.id
|
|||
|
const bool = id !== e.sender.id && !curWin.isDestroyed()
|
|||
|
if (bool) { // 除了消息发送窗口和销毁的窗口 其他都发送
|
|||
|
curWin.webContents.send('pinia-state-set', storeName, jsonStr)
|
|||
|
}
|
|||
|
}
|
|||
|
})
|
|||
|
// 用于监听-状态管理变化-初始同步
|
|||
|
ipcMain.handle('pinia-state-init', (e, wid, storeName, jsonStr) => {
|
|||
|
// console.log('pinia-state-init', jsonStr)
|
|||
|
const win = BrowserWindow.fromId(wid)
|
|||
|
win.webContents.send('pinia-state-set', storeName, jsonStr)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
// app 崩溃监听器
|
|||
|
function appWatchError() {
|
|||
|
// 渲染进程崩溃
|
|||
|
app.on('renderer-process-crashed', (event, webContents, killed) => {
|
|||
|
console.error(
|
|||
|
`APP-ERROR:renderer-process-crashed; event: ${JSON.stringify(event)}; webContents:${JSON.stringify(
|
|||
|
webContents
|
|||
|
)}; killed:${JSON.stringify(killed)}`
|
|||
|
)
|
|||
|
})
|
|||
|
|
|||
|
// GPU进程崩溃
|
|||
|
app.on('gpu-process-crashed', (event, killed) => {
|
|||
|
console.error(`APP-ERROR:gpu-process-crashed; event: ${JSON.stringify(event)}; killed: ${JSON.stringify(killed)}`)
|
|||
|
})
|
|||
|
|
|||
|
// 渲染进程结束
|
|||
|
app.on('render-process-gone', async (event, webContents, details) => {
|
|||
|
console.error(
|
|||
|
`APP-ERROR:render-process-gone; event: ${JSON.stringify(event)}; webContents:${JSON.stringify(
|
|||
|
webContents
|
|||
|
)}; details:${JSON.stringify(details)}`
|
|||
|
)
|
|||
|
})
|
|||
|
|
|||
|
// 子进程结束
|
|||
|
app.on('child-process-gone', async (event, details) => {
|
|||
|
console.error(`APP-ERROR:child-process-gone; event: ${JSON.stringify(event)}; details:${JSON.stringify(details)}`)
|
|||
|
})
|
|||
|
}
|