工具栏悬浮

This commit is contained in:
zdg 2024-07-26 12:48:03 +08:00
parent fe21b676a8
commit d50d4722aa
9 changed files with 207 additions and 65 deletions

View File

@ -3,10 +3,11 @@ import { join } from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils' import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset' import icon from '../../resources/icon.png?asset'
import File from './file' import File from './file'
import * as Tool from './tool'
// 代理 electron/remote // 代理 electron/remote
import remote from '@electron/remote/main' // 第一步引入remote // 第一步引入remote
remote.initialize() // 第二步: 初始化remote import remote from '@electron/remote/main'
// 第二步: 初始化remote
remote.initialize()
File({ app, shell, BrowserWindow, ipcMain }) File({ app, shell, BrowserWindow, ipcMain })
@ -63,6 +64,9 @@ function createMainWindow() {
mainWindow.on('ready-to-show', () => { mainWindow.on('ready-to-show', () => {
mainWindow.show() mainWindow.show()
}) })
mainWindow.on('closed', () => {
mainWindow = null
})
mainWindow.webContents.setWindowOpenHandler((details) => { mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url) shell.openExternal(details.url)
return { action: 'deny' } return { action: 'deny' }
@ -74,6 +78,8 @@ function createMainWindow() {
} else { } else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html')) mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
} }
// mainWindow.setAlwaysOnTop(true, "screen-saver") // 将窗口设置为顶层窗口
// mainWindow.setVisibleOnAllWorkspaces(true) // 如果窗口在所有工作区都可见
// 第三步: 开启remote服务 // 第三步: 开启remote服务
remote.enable(mainWindow.webContents) remote.enable(mainWindow.webContents)
} }
@ -162,7 +168,6 @@ app.on('ready', () => {
} }
loginWindow.destroy() loginWindow.destroy()
loginWindow = null loginWindow = null
Tool.setWin({mainWindow}) // 将主窗口传递到工具类中
}) })
// 打开登录窗口 // 打开登录窗口
ipcMain.on('openLoginWindow', () => { ipcMain.on('openLoginWindow', () => {
@ -178,8 +183,7 @@ app.on('ready', () => {
ipcMain.on('openWork', (e, data) => { ipcMain.on('openWork', (e, data) => {
createWork(data) createWork(data)
}) })
// zdg: 创建工具窗口-如 悬浮球
Tool.init()
// 打开-登录窗口 // 打开-登录窗口
createLoginWindow() createLoginWindow()
app.on('activate', function () { app.on('activate', function () {

View File

@ -14,7 +14,6 @@ let allWindow = {}
export function init() { export function init() {
// 创建工具-悬浮球 // 创建工具-悬浮球
ipcMain.on('tool-sphere:create', async(e, data) => { ipcMain.on('tool-sphere:create', async(e, data) => {
console.log('xxx', allWindow)
// console.log('测试xxxx', data) // console.log('测试xxxx', data)
await createTools(data) // 执行逻辑 await createTools(data) // 执行逻辑
e.reply('tool-sphere:create-reply', {code: 200, msg: 'success'}) // 返回结果 e.reply('tool-sphere:create-reply', {code: 200, msg: 'success'}) // 返回结果
@ -56,7 +55,7 @@ export function init() {
// url = 'https://www.baidu.com' // url = 'https://www.baidu.com'
console.log(urlAll) console.log(urlAll)
win.loadURL(urlAll) win.loadURL(urlAll)
// win.setFullScreen(true) // 设置窗口为全屏 win.setFullScreen(true) // 设置窗口为全屏
win.setIgnoreMouseEvents(true) // 忽略鼠标事件|使窗口不可选中 win.setIgnoreMouseEvents(true) // 忽略鼠标事件|使窗口不可选中
win.once('ready-to-show', () => { win.once('ready-to-show', () => {
win.show() win.show()
@ -77,14 +76,3 @@ export function setWin(win = {}) {
}) })
} }
} }
// 工具窗口-特殊区域恢复鼠标
function toolMouse(toolWin) {
ipcMain.on('tool-mouse', (e, data) => {
const { id } = data
const win = allWindow[id]
if (win) {
win.setIgnoreMouseEvents(false)
}
})
}

View File

@ -13,6 +13,12 @@ export const toolRouters = [
name: 'toolSphere', name: 'toolSphere',
meta: {title: '悬浮球'} meta: {title: '悬浮球'}
}, },
{
path: 'test',
component: () => import('@/views/tool/test.vue'),
name: 'toolTest',
meta: {title: '测试'}
},
] ]
}, },
{ {

View File

@ -118,6 +118,7 @@ export const useBoardStore = defineStore(
// init background | 初始化背景 // init background | 初始化背景
initBackground() { initBackground() {
const backgroundColor = FabricVue?.canvas?.backgroundColor const backgroundColor = FabricVue?.canvas?.backgroundColor
console.log('xxxx', backgroundColor, FabricVue?.canvas)
if (backgroundColor && typeof backgroundColor === 'string') { if (backgroundColor && typeof backgroundColor === 'string') {
const type = colorUtils.getColorFormat(backgroundColor) const type = colorUtils.getColorFormat(backgroundColor)
if (type === 'hex') { if (type === 'hex') {
@ -131,9 +132,13 @@ export const useBoardStore = defineStore(
this.backgroundOpacity = opacity this.backgroundOpacity = opacity
} }
} else if (FabricVue?.canvas) { } else if (FabricVue?.canvas) {
FabricVue.canvas.backgroundColor = 'rgba(255, 255, 255, 1)' if (this.backgroundColor) {
this.backgroundColor = 'rgba(255, 255, 255, 1)' FabricVue.canvas.backgroundColor = this.backgroundColor
this.backgroundOpacity = 1 } else {
FabricVue.canvas.backgroundColor = 'rgba(255, 255, 255, 1)'
this.backgroundColor = 'rgba(255, 255, 255, 1)'
this.backgroundOpacity = 1
}
} }
const backgroundImage = FabricVue?.canvas?.backgroundImage const backgroundImage = FabricVue?.canvas?.backgroundImage

View File

@ -1,11 +1,16 @@
/** /**
* @description: electron 封装的工具函数 * @description: electron 封装的工具函数
*/ */
const { ipcRenderer } = window.electron || {} // const { ipcRenderer } = window.electron || {}
// const {getCurrentWindow,BrowserWindow, shell, app} = require('@electron/remote'); // import { ipcRenderer } from 'electron' // 渲染器里面可以使用ipcRenderer
import remote from '@electron/remote' // const path = require('path')
const remote = require('@electron/remote') const Remote = require('@electron/remote')
console.log('xxxxx ', remote)
// 常用变量
const BaseUrl = process.env['ELECTRON_RENDERER_URL']+'/#'
const isDev = process.env.NODE_ENV !== 'production'
/** /**
* @description 消息发送-nodejs 消息发送 * @description 消息发送-nodejs 消息发送
* @form src/main/tool.js 来源 * @form src/main/tool.js 来源
@ -25,20 +30,117 @@ export function ipcMsgSend(key, data) {
ipcRenderer.send(key, data) ipcRenderer.send(key, data)
}) })
} }
/**
export function test() { * 创建-窗口 调用该方法
// console.log(BrowserWindow) * @param {*} type 类型
// const win = new BrowserWindow({ * tool-sphere 创建-悬浮球
// width: 400, height: 400 * @param {*} data 参数
// }) * @returns
// win.loadURL('https://www.baidu.com') */
// win.show() export const createWindow = async (type, data) => {
// win.on('close', () => { if (!type) return console.error('createWindow: type is null')
// win = null switch(type) {
// }) case 'tool-sphere': { // 创建-悬浮球
// const url = app.getPath('userData')+'/123.pdf' const option = data.option||{}
// console.log(app.getPath('userData')) const defOption = {
// shell.openExternal(url) frame: false, // 要创建无边框窗口
const win = getCurrentWindow() resizable: false, // 禁止窗口大小缩放
console.log(win) transparent: true, // 设置透明
alwaysOnTop: true, // 窗口是否总是显示在其他窗口之前
// parent: mainWin, // 父窗口
// autoClose: true, // 关闭窗口后自动关闭
}
data.option = {...defOption, ...option}
const win = await toolWindow(data)
win.show()
win.setFullScreen(true) // 设置窗口为全屏
win.setIgnoreMouseEvents(true, {forward: true}) // 忽略鼠标事件但是事件继续传递给窗口
win.setAlwaysOnTop(true,'screen-saver') // 将窗口设置为顶层窗口
win.setVisibleOnAllWorkspaces(true) // 如果窗口在所有工作区都可见
// win.webContents.openDevTools() // 打开调试工具
eventHandles(type, win) // 事件监听处理
return win
}
default:
break
}
}
/**
* @description: 基础-创建工具-窗口
* @param {*} url 路由地址
* @param {number} [width=800] 窗口宽度
* @param {number} [height=600] 窗口高度
* @param {{}} [option={}] 自定义选项
* @author: zdg
* @date 2021-07-05 14:07:01
*/
export function toolWindow({url, isFile, isConsole, option={}}) {
// width = window.screen.width
let width = option?.width || 800
let height = option?.height || 600
const mainWin = Remote.getCurrentWindow() // 获取主窗口对象
const devUrl = `${BaseUrl}${url}`
const buildUrl = `file://${__dirname}/index.html${url}`
const urlAll = isDev ? devUrl : buildUrl
return new Promise((resolve) => {
const config = {
width, height,
type: 'toolbar', // 创建的窗口类型为工具栏窗口
webPreferences: {
preload: '@root/src/preload/index.js',
nodeIntegration: true, // nodeApi调用
contextIsolation: false, // 沙箱取消
// webSecurity: false // 跨域关闭
},
...option
}
// 创建-新窗口
let win = new Remote.BrowserWindow(config)
if (!!isFile) win.loadFile(urlAll) // 加载文件
else win.loadURL(urlAll) // 加载url
win.once('ready-to-show', () => {resolve(win)})
// 主窗口关闭事件
mainWin.once('closed', () => { win.destroy()})
// 内部监听器
win.webContents.on('did-finish-load', () => {})
// 内部监听器-是否打印
if (!!isConsole) {
win.webContents.on('console-message', (e,leve,m,lin,s) => {
console.log('console-msg: ', m)
})
}
})
}
/**
* 窗口创建-事件处理
* @param {*} type 事件类型
* @param {*} win 窗口对象
*/
const eventHandles = (type, win) => {
// 公共方法
const publicMethods = ({onClosed}) => {
// 监听关闭事件
Remote.ipcMain.once('close-window', () => {win.destroy()})
win.on('closed', () => {!!onClosed && onClosed();win = null})
}
switch(type) {
case 'tool-sphere': { // 创建-悬浮球
// 监听设置穿透
const setIgnore = (_, ignore) => {win.setIgnoreMouseEvents(ignore, {forward: true})}
Remote.ipcMain.on('tool-sphere:set:ignore', setIgnore)
// 关闭窗口
Remote.ipcMain.once('tool-sphere:close', () => { win.destroy() })
// 放大监听-测试
Remote.ipcMain.once('maximize-window', () => {
win.destroy()
console.log('关闭窗口')
})
const on = {
onClosed: () => {Remote.ipcMain.off('tool-sphere:set:ignore', setIgnore)}
}
publicMethods(on) // 加载公共方法
break}
default:
break
}
} }

View File

@ -16,7 +16,7 @@
</div> </div>
<!-- 上传弹窗 --> <!-- 上传弹窗 -->
<uploadDialog v-model="isDialogOpen" @submitFile="submitFile" /> <uploadDialog v-model="isDialogOpen" @submitFile="submitFile" />
<!-- <el-button @click="testClick">测试</el-button> --> <el-button @click="testClick">测试</el-button>
</template> </template>
<script setup> <script setup>
@ -27,11 +27,11 @@ import ResoureSearch from './container/resoure-search.vue'
import ResoureList from './container/resoure-list.vue' import ResoureList from './container/resoure-list.vue'
import uploadDialog from '@/components/upload-dialog/index.vue' import uploadDialog from '@/components/upload-dialog/index.vue'
import uploaderState from '@/store/modules/uploader' import uploaderState from '@/store/modules/uploader'
import { ipcMsgSend, test } from '@/utils/tool' import { createWindow } from '@/utils/tool'
const sourceStore = useResoureStore() const sourceStore = useResoureStore()
const isDialogOpen = ref(false) const isDialogOpen = ref(false)
const testClick = () => {console.log('xxxx');test()}
const openDialog = () => { const openDialog = () => {
isDialogOpen.value = true isDialogOpen.value = true
} }
@ -40,6 +40,11 @@ onMounted(async () => {
// const res = await ipcMsgSend('tool-sphere:create', params) // const res = await ipcMsgSend('tool-sphere:create', params)
// console.log('', res) // console.log('', res)
}) })
const testClick = async() => {
const params = { url: '/tool/sphere' }
const win = await createWindow('tool-sphere', params)
console.log('消息返回:', win)
}
// //
const getData = (data) => { const getData = (data) => {
const { textBook, node } = data const { textBook, node } = data

View File

@ -0,0 +1,24 @@
<template>
<canvas ref="canvasRef" />
<slot></slot>
</template>
<script setup>
//
import { ref, onMounted } from 'vue'
import { FabricVue } from '@/plugins/fabric'
import { useBoardStore } from '@/store/modules/draw'
const canvasRef = ref(null)
onMounted(async() => {
if (canvasRef.value) {
useBoardStore().backgroundColor = 'transparent'
const option = { freeDrawingCursor: 'default' }
await FabricVue.initCanvas(canvasRef.value, option)
// FabricVue.canvas.backgroundColor = 'transparent'
// FabricVue.canvas.setWidth(500)
// FabricVue.canvas.setHeight(500)
}
})
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,11 +1,10 @@
<template> <template>
<div class="warp-all"> <div class="warp-all">
<board-vue></board-vue>
<el-row class="tool-bottom-all"> <!-- 底部工具栏 -->
<el-row id="test" class="tool-bottom-all" @mouseenter="mouseChange(0)" @mouseleave="mouseChange(1)">
<el-col :span="3" class="flex justify-center items-center"> <el-col :span="3" class="flex justify-center items-center">
<div class="c-logo"> <div class="c-logo"><el-image :src="logo" @click="tabChange('close')" /></div>
<el-image :src="logo"></el-image>
</div>
</el-col> </el-col>
<el-col :span="20"> <el-col :span="20">
<el-segmented class="c-btns" v-model="tabActive" :options="btnList" size="large" block <el-segmented class="c-btns" v-model="tabActive" :options="btnList" size="large" block
@ -24,8 +23,13 @@
<script setup> <script setup>
// electron // electron
import { ref } from 'vue' import { onMounted, ref } from 'vue'
import logo from '@root/resources/icon.png' import logo from '@root/resources/icon.png' // logo
import boardVue from './components/board.vue'
// const Remote = require('@electron/remote') // remote
const { ipcRenderer } = require('electron')
const tabActive = ref('select') const tabActive = ref('select')
const btnList = [ const btnList = [
{ label: '选择', value: 'select', icon: 'icon-mouse' }, { label: '选择', value: 'select', icon: 'icon-mouse' },
@ -38,7 +42,7 @@ const btnList = [
// ==== === // ==== ===
const tabChange = (val) => { // tab-change const tabChange = (val) => { // tab-change
console.log(val) console.log('xxxx', val)
switch (val) { switch (val) {
case 'brush': case 'brush':
break break
@ -50,10 +54,18 @@ const tabChange = (val) => { // 切换tab-change
break break
case 'more': case 'more':
break break
case 'close':
ipcRenderer.send('tool-sphere:close')
break
default: default:
break break
} }
} }
const mouseChange = (bool) => { // 穿
let resBool = false
if (tabActive.value == 'select') resBool = !!bool
ipcRenderer.send('tool-sphere:set:ignore', resBool)
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,26 +1,22 @@
<template> <template>
<div> <canvas class="test" ref="canvasRef" />
xxxxx
</div>
<canvas ref="canvasRef" />
</template> </template>
<script setup> <script setup>
// electron // electron
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { FabricVue } from '@/plugins/fabric' import { FabricVue } from '@/plugins/fabric'
// import * as fabricStore from '@/store/modules/draw' import { useBoardStore } from '@/store/modules/draw'
// let useDrawStore = fabricStore.useDrawStore()
// console.log(useDrawStore)
let canvasRef = ref(null) let canvasRef = ref(null)
onMounted(async() => { onMounted(async() => {
console.log(canvasRef, FabricVue) console.log(canvasRef, FabricVue)
if (canvasRef.value) { if (canvasRef.value) {
const option = { width: 400, height: 400, freeDrawingCursor: 'default' } useBoardStore().backgroundColor = 'transparent'
const option = { freeDrawingCursor: 'default' }
await FabricVue.initCanvas(canvasRef.value, option) await FabricVue.initCanvas(canvasRef.value, option)
FabricVue.canvas.setWidth(500) // FabricVue.canvas.setWidth(500)
FabricVue.canvas.setHeight(500) // FabricVue.canvas.setHeight(500)
} }
}) })