11 changed files with 601 additions and 71 deletions
@ -0,0 +1,63 @@ |
|||||
|
import Shared from "./share" |
||||
|
import { Menu, Tray, ipcMain, BrowserWindow, App } from "electron" |
||||
|
const path = require("path") |
||||
|
|
||||
|
// 隐藏主窗口,并创建托盘,绑定关闭事件
|
||||
|
export default function setTray(app: App, mainWindow: BrowserWindow) { |
||||
|
if (Shared.data.miniWindow) { |
||||
|
mainWindow.hide() |
||||
|
return |
||||
|
} |
||||
|
// 用一个 Tray 来表示一个图标,这个图标处于正在运行的系统的通知区
|
||||
|
// 通常被添加到一个 context menu 上.
|
||||
|
// 系统托盘右键菜单
|
||||
|
const trayMenuTemplate = [ |
||||
|
{ |
||||
|
// 系统托盘图标目录
|
||||
|
label: "打开主窗口", |
||||
|
click: () => { |
||||
|
mainWindow.show() |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
// 系统托盘图标目录
|
||||
|
label: "打开悬浮窗", |
||||
|
click: () => { |
||||
|
ipcMain.emit("showSuspensionWindow") |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
// 系统托盘图标目录
|
||||
|
label: "退出", |
||||
|
click: () => { |
||||
|
Shared.data.forceClose = true |
||||
|
app.quit() |
||||
|
}, |
||||
|
}, |
||||
|
] |
||||
|
// 设置系统托盘图标
|
||||
|
const iconPath = path.join(__static, "/icon.png") |
||||
|
|
||||
|
Shared.data.miniWindow = new Tray(iconPath) |
||||
|
|
||||
|
// 图标的上下文菜单
|
||||
|
const contextMenu = Menu.buildFromTemplate(trayMenuTemplate) |
||||
|
|
||||
|
// 展示主窗口,隐藏主窗口 mainWindow.hide()
|
||||
|
mainWindow.hide() |
||||
|
|
||||
|
// 设置托盘悬浮提示
|
||||
|
Shared.data.miniWindow.setToolTip("never forget") |
||||
|
|
||||
|
// 设置托盘菜单
|
||||
|
Shared.data.miniWindow.setContextMenu(contextMenu) |
||||
|
|
||||
|
// 单击托盘小图标显示应用
|
||||
|
Shared.data.miniWindow.on("double-click", () => { |
||||
|
// 显示主程序
|
||||
|
mainWindow.show() |
||||
|
// 关闭托盘显示
|
||||
|
// Shared.data.miniWindow.destroy();
|
||||
|
}) |
||||
|
return Shared.data.miniWindow |
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
import { ipcMain, dialog } from "electron" |
||||
|
|
||||
|
/** |
||||
|
* 格式:@类型:扩展:函数 |
||||
|
*/ |
||||
|
|
||||
|
// 保存数据
|
||||
|
ipcMain.on("@func:buildin:close", data => { |
||||
|
// dialog.showMessageBox(
|
||||
|
// {
|
||||
|
// type: "info",
|
||||
|
// title: "Information",
|
||||
|
// defaultId: 0,
|
||||
|
// cancelId: 0,
|
||||
|
// message: "确定要关闭吗?" + data,
|
||||
|
// buttons: ["没事", "最小化到托盘", "直接退出"],
|
||||
|
// },
|
||||
|
// index => {}
|
||||
|
// )
|
||||
|
}) |
@ -0,0 +1,121 @@ |
|||||
|
import Shared from "./share" |
||||
|
import { BrowserWindow, ipcMain, screen, Menu, shell, webContents } from "electron" |
||||
|
// webContents
|
||||
|
console.log(webContents.getAllWebContents()) |
||||
|
|
||||
|
const window: any = null //BrowserWindow.fromWebContents(webContents.getFocusedWebContents())
|
||||
|
const winURL = |
||||
|
process.env.NODE_ENV === "development" ? `http://localhost:${process.env.PORT}/#/float` : `file://${__dirname}/index.html#/float` |
||||
|
|
||||
|
ipcMain.on("@float:setPosition", (event, x, y) => { |
||||
|
Shared.data.floatWindow?.setPosition(x, y) |
||||
|
}) |
||||
|
|
||||
|
ipcMain.on("showSuspensionWindow", () => { |
||||
|
console.log(24324) |
||||
|
|
||||
|
if (Shared.data.floatWindow) { |
||||
|
if (Shared.data.floatWindow.isVisible()) { |
||||
|
createSuspensionWindow() |
||||
|
} else { |
||||
|
Shared.data.floatWindow.showInactive() |
||||
|
} |
||||
|
} else { |
||||
|
createSuspensionWindow() |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
ipcMain.on("createSuspensionMenu", e => { |
||||
|
const rightM = Menu.buildFromTemplate([ |
||||
|
{ label: "开始全部任务", enabled: false }, |
||||
|
{ label: "暂停全部任务", enabled: false }, |
||||
|
{ |
||||
|
label: "本次传输完自动关机", |
||||
|
click: () => { |
||||
|
ipcMain.emit("@func:buildin:saveData", 32232) |
||||
|
}, |
||||
|
}, |
||||
|
{ type: "separator" }, |
||||
|
{ |
||||
|
label: "隐藏悬浮窗", |
||||
|
click: () => { |
||||
|
if (window) { |
||||
|
window.webContents.send("hideSuspension", false) |
||||
|
} |
||||
|
Shared.data.floatWindow.hide() |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: "打开主窗口", |
||||
|
click: () => { |
||||
|
// && !Shared.data.mainWindow.isVisible()
|
||||
|
if (Shared.data.mainWindow) { |
||||
|
Shared.data.mainWindow.show() |
||||
|
} |
||||
|
// window.webContents.send('hideSuspension', false)
|
||||
|
}, |
||||
|
}, |
||||
|
{ type: "separator" }, |
||||
|
{ |
||||
|
label: "加入qq群", |
||||
|
click: () => { |
||||
|
shell.openExternal( |
||||
|
"tencent://groupwpa/?subcmd=all¶m=7B2267726F757055696E223A3831343237303636392C2274696D655374616D70223A313533393531303138387D0A" |
||||
|
) |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: "GitHub地址", |
||||
|
click: () => { |
||||
|
shell.openExternal("https://github.com/lihaotian0607/auth") |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: "退出软件", |
||||
|
click: () => { |
||||
|
Shared.data.mainWindow.close() |
||||
|
}, |
||||
|
}, |
||||
|
]) |
||||
|
rightM.popup({}) |
||||
|
}) |
||||
|
|
||||
|
function createSuspensionWindow() { |
||||
|
Shared.data.floatWindow = new BrowserWindow({ |
||||
|
width: 102, // 悬浮窗口的宽度 比实际DIV的宽度要多2px 因为有1px的边框
|
||||
|
height: 27, // 悬浮窗口的高度 比实际DIV的高度要多2px 因为有1px的边框
|
||||
|
type: "toolbar", // 创建的窗口类型为工具栏窗口
|
||||
|
frame: false, // 要创建无边框窗口
|
||||
|
resizable: false, // 禁止窗口大小缩放
|
||||
|
show: false, // 先不让窗口显示
|
||||
|
webPreferences: { |
||||
|
devTools: false, // 关闭调试工具
|
||||
|
nodeIntegration: true, |
||||
|
contextIsolation: false, |
||||
|
}, |
||||
|
transparent: true, // 设置透明
|
||||
|
alwaysOnTop: true, // 窗口是否总是显示在其他窗口之前
|
||||
|
}) |
||||
|
const size = screen.getPrimaryDisplay().workAreaSize // 获取显示器的宽高
|
||||
|
const winSize = Shared.data.floatWindow.getSize() // 获取窗口宽高
|
||||
|
// 设置窗口的位置 注意x轴要桌面的宽度 - 窗口的宽度
|
||||
|
Shared.data.floatWindow.setPosition(size.width - winSize[0], 100) |
||||
|
Shared.data.floatWindow.setPosition(size.width / 2, size.height / 2) |
||||
|
Shared.data.floatWindow.loadURL(winURL) |
||||
|
|
||||
|
Shared.data.floatWindow.once("ready-to-show", () => { |
||||
|
Shared.data.floatWindow.show() |
||||
|
}) |
||||
|
Shared.data.floatWindow.on("double-click", () => { |
||||
|
alert(123) |
||||
|
}) |
||||
|
Shared.data.floatWindow.on("close", () => { |
||||
|
Shared.data.floatWindow = null |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
ipcMain.on("hideSuspensionWindow", () => { |
||||
|
if (Shared.data.floatWindow) { |
||||
|
Shared.data.floatWindow.hide() |
||||
|
} |
||||
|
}) |
@ -1,54 +1,134 @@ |
|||||
/** |
/** |
||||
* electron 主文件 |
* electron 主文件 |
||||
*/ |
*/ |
||||
// import "@src/common/patch"
|
'use strict' |
||||
import Shared from "./share" |
import Shared from './share' |
||||
const { join } = require("path") |
import setTray from './disk' |
||||
const { app, BrowserWindow } = require("electron") |
// import '../renderer/store'
|
||||
import "./menu" |
import './facilities' |
||||
|
import { app, BrowserWindow, dialog } from 'electron' |
||||
|
|
||||
Shared.data = { |
Shared.data = { |
||||
mainWindow: null, |
mainWindow: null, |
||||
floatWindow: null, |
floatWindow: null, |
||||
miniWindow: null, |
miniWindow: null, |
||||
forceClose: false, |
forceClose: false |
||||
} |
} |
||||
|
console.log('asdasadsads') |
||||
|
/** |
||||
|
* Set `__static` path to static files in production |
||||
|
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
|
||||
|
*/ |
||||
|
let isDev = process.env.NODE_ENV == "development" ? true : false |
||||
|
|
||||
let isDev = process.env.NODE_ENV == "development" ? true : false |
if (!isDev) { |
||||
|
// @ts-ignore
|
||||
|
global.__static = require("path").join(__dirname, "/static").replace(/\\/g, "\\\\") |
||||
|
} |
||||
|
|
||||
if (!isDev) { |
|
||||
// @ts-ignore
|
const winURL = process.env.NODE_ENV === 'development' ? `http://localhost:${process.env.PORT}/#/` : `file://${__dirname}/index.html` |
||||
global.__static = require("path").join(__dirname, "/static").replace(/\\/g, "\\\\") |
let lastChoice = -1 |
||||
} |
|
||||
|
function createWindow() { |
||||
function createWin() { |
/** |
||||
// 创建浏览器窗口dsaasdad
|
* Initial window options |
||||
|
*/ |
||||
Shared.data.mainWindow = new BrowserWindow({ |
Shared.data.mainWindow = new BrowserWindow({ |
||||
height: 800, |
height: 400, |
||||
useContentSize: true, |
useContentSize: true, |
||||
width: 900, |
width: 600, |
||||
// resizable: false,
|
resizable: true, |
||||
// minWidth: 450,
|
minWidth: 450, |
||||
// minHeight: 400,
|
minHeight: 400, |
||||
// frame: false,
|
// frame: false,
|
||||
// transparent: true,
|
// transparent: true,
|
||||
alwaysOnTop: true, |
alwaysOnTop: false, |
||||
icon: __static + "/icon.png", |
|
||||
webPreferences: { |
webPreferences: { |
||||
// 下面两个必须这么用,看a.md的文档
|
|
||||
nodeIntegration: true, |
nodeIntegration: true, |
||||
contextIsolation: false, |
contextIsolation: false |
||||
// 预加载动画
|
} |
||||
// preload: join(__dirname, "../../src/preload/index.js"),
|
|
||||
}, |
|
||||
}) |
}) |
||||
|
|
||||
const URL = app.isPackaged |
Shared.data.mainWindow.loadURL(winURL) |
||||
? `file://${__dirname}/index.html` // vite 构建后的静态文件地址
|
Shared.data.mainWindow.on('close', (event:any) => { |
||||
: `http://localhost:${process.env.PORT}/#/` // vite 启动的服务器地址
|
if (Shared.data.forceClose) { |
||||
// : `http://localhost:8080/#/` // vite 启动的服务器地址
|
Shared.data.mainWindow = null |
||||
|
app.quit() |
||||
Shared.data.mainWindow?.loadURL(URL) |
} else if (Shared.data.mainWindow) { |
||||
|
if (lastChoice === 1) { |
||||
|
if (Shared.data.miniWindow) { |
||||
|
Shared.data.mainWindow.hide() // 调用 最小化实例方法
|
||||
|
} else { |
||||
|
setTray(app, Shared.data.mainWindow) |
||||
|
} |
||||
|
event.preventDefault() |
||||
|
} else { |
||||
|
const choice = dialog.showMessageBoxSync(Shared.data.mainWindow, { |
||||
|
type: 'info', |
||||
|
title: 'Information', |
||||
|
defaultId: 0, |
||||
|
cancelId: 0, |
||||
|
message: '确定要关闭吗?', |
||||
|
buttons: ['没事', '最小化到托盘', '直接退出'] |
||||
|
}) |
||||
|
if (choice === 1) { |
||||
|
lastChoice = 1 |
||||
|
if (Shared.data.miniWindow) { |
||||
|
Shared.data.mainWindow.hide() // 调用 最小化实例方法
|
||||
|
} else { |
||||
|
setTray(app, Shared.data.mainWindow) |
||||
|
} |
||||
|
event.preventDefault() |
||||
|
} else if (choice === 2) { |
||||
|
Shared.data.mainWindow = null |
||||
|
// app.quit()
|
||||
|
// 不要用quit();试了会弹两次
|
||||
|
Shared.data.forceClose = true |
||||
|
app.quit() // exit()直接关闭客户端,不会执行quit();
|
||||
|
} else { |
||||
|
event.preventDefault() |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
} |
} |
||||
|
|
||||
app.whenReady().then(createWin) |
const gotTheLock = app.requestSingleInstanceLock() |
||||
|
if (!gotTheLock) { |
||||
|
app.exit() |
||||
|
} else { |
||||
|
require('./menu') |
||||
|
require('./float') |
||||
|
|
||||
|
app.on('second-instance', (event, commandLine, workingDirectory) => { |
||||
|
// 当运行第二个实例时,将会聚焦到mainWindow这个窗口
|
||||
|
if (Shared.data.mainWindow) { |
||||
|
if (Shared.data.mainWindow.isMinimized()) Shared.data.mainWindow.restore() |
||||
|
Shared.data.mainWindow.focus() |
||||
|
Shared.data.mainWindow.show() |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
app.on('ready', createWindow) |
||||
|
|
||||
|
app.on('before-quit', event => { |
||||
|
if (Shared.data.forceClose) { |
||||
|
app.exit() |
||||
|
} else { |
||||
|
event.preventDefault() |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
app.on('window-all-closed', () => { |
||||
|
if (process.platform !== 'darwin') { |
||||
|
app.exit() |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
app.on('activate', () => { |
||||
|
if (Shared.data.mainWindow === null) { |
||||
|
createWindow() |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
@ -0,0 +1,66 @@ |
|||||
|
import electron from "electron" |
||||
|
|
||||
|
const BrowserWindow = electron.BrowserWindow |
||||
|
const Menu = electron.Menu |
||||
|
const app = electron.app |
||||
|
const dialog = electron.dialog |
||||
|
const ipcMain = electron.ipcMain |
||||
|
|
||||
|
let newwin:electron.BrowserWindow|null = null |
||||
|
|
||||
|
let template = [ |
||||
|
{ |
||||
|
label: "关于", |
||||
|
click: function (item:any, focusedWindow:any) { |
||||
|
// https://www.electronjs.org/docs/api/browser-window#winsetmenubarvisibilityvisible-windows-linux
|
||||
|
if (focusedWindow && !newwin) { |
||||
|
newwin = new BrowserWindow({ |
||||
|
width: 600, |
||||
|
height: 200, |
||||
|
// modal: true,
|
||||
|
show: false, |
||||
|
resizable: true, |
||||
|
parent: focusedWindow, // win是主窗口
|
||||
|
//
|
||||
|
webPreferences: { |
||||
|
// 下面两个必须这么用,看a.md的文档
|
||||
|
nodeIntegration: true, |
||||
|
contextIsolation: false, |
||||
|
// 预加载动画
|
||||
|
// preload: join(__dirname, "../../src/preload/index.js"),
|
||||
|
}, |
||||
|
}) |
||||
|
// 隐藏菜单
|
||||
|
newwin.setMenuBarVisibility(false) |
||||
|
newwin.loadURL(process.env.NODE_ENV === "development" ? `http://localhost:${process.env.PORT}/#/about` : `file://${__dirname}/index.html#/about`); |
||||
|
newwin.on("ready-to-show", () => { |
||||
|
newwin?.show() |
||||
|
}) |
||||
|
newwin.on("closed", () => { |
||||
|
newwin = null |
||||
|
}) |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
] |
||||
|
|
||||
|
// if (process.platform === 'darwin') {
|
||||
|
//
|
||||
|
// }
|
||||
|
//
|
||||
|
// if (process.platform === 'win32') {
|
||||
|
//
|
||||
|
// }
|
||||
|
app.on("ready", function () { |
||||
|
const menu = Menu.buildFromTemplate(template) |
||||
|
Menu.setApplicationMenu(menu) |
||||
|
}) |
||||
|
app.on("browser-window-created", function () { |
||||
|
// let reopenMenuItem = findReopenMenuItem()
|
||||
|
// if (reopenMenuItem) reopenMenuItem.enabled = false
|
||||
|
}) |
||||
|
app.on("window-all-closed", function () { |
||||
|
app.exit() |
||||
|
// let reopenMenuItem = findReopenMenuItem()
|
||||
|
// if (reopenMenuItem) reopenMenuItem.enabled = true
|
||||
|
}) |
@ -0,0 +1,10 @@ |
|||||
|
.view-float { |
||||
|
width: 100px; |
||||
|
height: 25px; |
||||
|
line-height: 25px; |
||||
|
background-color: #fff; |
||||
|
position: fixed; |
||||
|
overflow: auto; |
||||
|
user-select: none; |
||||
|
border: 1px solid red; |
||||
|
} |
@ -0,0 +1,43 @@ |
|||||
|
import React, { MouseEventHandler, useEffect } from "react" |
||||
|
import electron from "@/plugins/electron" |
||||
|
import style from "./index.module.scss" |
||||
|
import { useLocation, Route, Switch, useHistory } from "react-router-dom" |
||||
|
|
||||
|
export default function Float(props: any) { |
||||
|
useEffect(() => { |
||||
|
// let win = electron.remote.getCurrentWindow()
|
||||
|
let biasX = 0 |
||||
|
let biasY = 0 |
||||
|
document.addEventListener("mousedown", function (e) { |
||||
|
switch (e.button) { |
||||
|
case 0: |
||||
|
biasX = e.x |
||||
|
biasY = e.y |
||||
|
document.addEventListener("mousemove", moveEvent) |
||||
|
break |
||||
|
case 2: |
||||
|
electron.ipcRenderer.send("createSuspensionMenu") |
||||
|
break |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
document.addEventListener("mouseup", function () { |
||||
|
biasX = 0 |
||||
|
biasY = 0 |
||||
|
document.removeEventListener("mousemove", moveEvent) |
||||
|
}) |
||||
|
|
||||
|
function moveEvent(e: any) { |
||||
|
electron.ipcRenderer.send('@float:setPosition', e.screenX - biasX, e.screenY - biasY) |
||||
|
// win.setPosition(e.screenX - biasX, e.screenY - biasY)
|
||||
|
} |
||||
|
}, []) |
||||
|
function dblclick(e: MouseEventHandler<HTMLDivElement>) { |
||||
|
alert("asd") |
||||
|
} |
||||
|
return ( |
||||
|
<div className={style["view-float"]} onDoubleClick={(e: any) => dblclick(e)}> |
||||
|
悬浮窗 |
||||
|
</div> |
||||
|
) |
||||
|
} |
Loading…
Reference in new issue