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 主文件 |
|||
*/ |
|||
// import "@src/common/patch"
|
|||
import Shared from "./share" |
|||
const { join } = require("path") |
|||
const { app, BrowserWindow } = require("electron") |
|||
import "./menu" |
|||
'use strict' |
|||
import Shared from './share' |
|||
import setTray from './disk' |
|||
// import '../renderer/store'
|
|||
import './facilities' |
|||
import { app, BrowserWindow, dialog } from 'electron' |
|||
|
|||
Shared.data = { |
|||
mainWindow: null, |
|||
floatWindow: 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
|
|||
global.__static = require("path").join(__dirname, "/static").replace(/\\/g, "\\\\") |
|||
} |
|||
|
|||
function createWin() { |
|||
// 创建浏览器窗口dsaasdad
|
|||
|
|||
const winURL = process.env.NODE_ENV === 'development' ? `http://localhost:${process.env.PORT}/#/` : `file://${__dirname}/index.html` |
|||
let lastChoice = -1 |
|||
|
|||
function createWindow() { |
|||
/** |
|||
* Initial window options |
|||
*/ |
|||
Shared.data.mainWindow = new BrowserWindow({ |
|||
height: 800, |
|||
height: 400, |
|||
useContentSize: true, |
|||
width: 900, |
|||
// resizable: false,
|
|||
// minWidth: 450,
|
|||
// minHeight: 400,
|
|||
width: 600, |
|||
resizable: true, |
|||
minWidth: 450, |
|||
minHeight: 400, |
|||
// frame: false,
|
|||
// transparent: true,
|
|||
alwaysOnTop: true, |
|||
icon: __static + "/icon.png", |
|||
alwaysOnTop: false, |
|||
webPreferences: { |
|||
// 下面两个必须这么用,看a.md的文档
|
|||
nodeIntegration: true, |
|||
contextIsolation: false, |
|||
// 预加载动画
|
|||
// preload: join(__dirname, "../../src/preload/index.js"),
|
|||
}, |
|||
contextIsolation: false |
|||
} |
|||
}) |
|||
|
|||
const URL = app.isPackaged |
|||
? `file://${__dirname}/index.html` // vite 构建后的静态文件地址
|
|||
: `http://localhost:${process.env.PORT}/#/` // vite 启动的服务器地址
|
|||
// : `http://localhost:8080/#/` // vite 启动的服务器地址
|
|||
|
|||
Shared.data.mainWindow?.loadURL(URL) |
|||
Shared.data.mainWindow.loadURL(winURL) |
|||
Shared.data.mainWindow.on('close', (event:any) => { |
|||
if (Shared.data.forceClose) { |
|||
Shared.data.mainWindow = null |
|||
app.quit() |
|||
} 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