zdg #105
|
@ -13,10 +13,7 @@ import {
|
||||||
onMounted,
|
onMounted,
|
||||||
watch,
|
watch,
|
||||||
reactive,
|
reactive,
|
||||||
defineProps,
|
|
||||||
defineExpose,
|
|
||||||
nextTick,
|
nextTick,
|
||||||
defineEmits
|
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
|
@ -151,7 +151,7 @@ const savaDataStore = () => {
|
||||||
Promise.all(promises).then(res=>{
|
Promise.all(promises).then(res=>{
|
||||||
toolState.isPdfWin=false
|
toolState.isPdfWin=false
|
||||||
toolState.showBoardAll=true //恢复默认值
|
toolState.showBoardAll=true //恢复默认值
|
||||||
// ipcRenderer.send('tool-sphere:reset') //重置tool状态
|
ipcRenderer.invoke('tool-sphere:reset') //重置tool状态
|
||||||
ipcRenderer.send('open-PDF:minimize')
|
ipcRenderer.send('open-PDF:minimize')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ const initPdfone = async () => {
|
||||||
}
|
}
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
try {
|
try {
|
||||||
// 获取页数
|
// 创建canvas转化成图片
|
||||||
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise
|
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise
|
||||||
numPagesTotal.value = pdf.numPages
|
numPagesTotal.value = pdf.numPages
|
||||||
// 初始化fabriccanvas
|
// 初始化fabriccanvas
|
||||||
|
@ -292,7 +292,7 @@ onMounted(async () => {
|
||||||
canvas1FabricVue.value = canvas2
|
canvas1FabricVue.value = canvas2
|
||||||
window.test = { canvas1, canvas2 }
|
window.test = { canvas1, canvas2 }
|
||||||
emit('update:numPagesTotal', pdf.numPages)
|
emit('update:numPagesTotal', pdf.numPages)
|
||||||
//加载接口数据
|
|
||||||
if (props.pdfObj.allPageData.length) {
|
if (props.pdfObj.allPageData.length) {
|
||||||
props.pdfObj.allPageData.forEach((a) => {
|
props.pdfObj.allPageData.forEach((a) => {
|
||||||
if (a.pageNum == 1 || a.pageNum == 2) {
|
if (a.pageNum == 1 || a.pageNum == 2) {
|
||||||
|
@ -305,10 +305,15 @@ onMounted(async () => {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
ElMessage.error('pdf文件错误')
|
ElMessage.error('pdf文件错误')
|
||||||
}
|
}
|
||||||
|
setToolStatus()
|
||||||
// 监听2个canvas事件
|
// 监听2个canvas事件
|
||||||
// handleevent(fabriccanvas.value, imgarr)
|
// handleevent(fabriccanvas.value, imgarr)
|
||||||
// handleevent(fabriccanvas1.value, imgarr, 'two')
|
// handleevent(fabriccanvas1.value, imgarr, 'two')
|
||||||
})
|
})
|
||||||
|
// zdg: 设置-底部工具栏-状态
|
||||||
|
const setToolStatus = () => {
|
||||||
|
toolState.showBoardAll = false
|
||||||
|
}
|
||||||
// 判断元素是否加载完成
|
// 判断元素是否加载完成
|
||||||
const handleMode = (vale,type)=>{
|
const handleMode = (vale,type)=>{
|
||||||
if(vale=='select'){
|
if(vale=='select'){
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
<el-button type="primary" @click="editUserInfo">
|
<el-button type="primary" @click="editUserInfo" :loading="subjectLoading">
|
||||||
确定
|
确定
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import { listEvaluation } from '@/api/subject'
|
import { listEvaluation } from '@/api/subject'
|
||||||
import { updateUserInfo } from '@/api/system/user'
|
import { updateUserInfo } from '@/api/system/user'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
|
@ -42,12 +42,20 @@ const userStore = useUserStore()
|
||||||
const { userId, userName } = userStore.user
|
const { userId, userName } = userStore.user
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
loginData: {
|
||||||
|
type: Object,
|
||||||
|
default(){
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const subjectLoading = ref(false)
|
||||||
|
|
||||||
// 定义要发送的emit事件
|
// 定义要发送的emit事件
|
||||||
const emit = defineEmits(['update:modelValue', 'onSuccess'])
|
const emit = defineEmits(['update:modelValue', 'onSuccess'])
|
||||||
|
|
||||||
|
@ -111,8 +119,18 @@ const editUserInfo = async () =>{
|
||||||
edustage: gradeVal.value,
|
edustage: gradeVal.value,
|
||||||
edusubject: subjectVal.value
|
edusubject: subjectVal.value
|
||||||
}
|
}
|
||||||
await updateUserInfo(data)
|
|
||||||
await userStore.getInfo()
|
// 修改之后需要重新登录 查询用户信息,否则不登录 查询的用户信息是未修改之前的
|
||||||
|
// 接口如此,我也不知道为啥要这样
|
||||||
|
subjectLoading.value = true
|
||||||
|
try {
|
||||||
|
//修改用户信息
|
||||||
|
await updateUserInfo(data)
|
||||||
|
await userStore.login(props.loginData)
|
||||||
|
await userStore.getInfo()
|
||||||
|
} finally {
|
||||||
|
subjectLoading.value = false
|
||||||
|
}
|
||||||
emit('onSuccess')
|
emit('onSuccess')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,5 +166,7 @@ watch(() => props.modelValue, (newVal) => {
|
||||||
-webkit-app-region: no-drag;
|
-webkit-app-region: no-drag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-select-dropdown__item{
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
|
@ -1,7 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* 共享数据状态-多窗口
|
* 共享数据状态-多窗口
|
||||||
*/
|
*/
|
||||||
const { ipcRenderer } = require('electron') // app使用
|
const isNode = typeof require !== 'undefined' // 是否支持node函数
|
||||||
|
const { ipcRenderer } = isNode?require('electron'):{} // app使用
|
||||||
export function shareStorePlugin({store}) {
|
export function shareStorePlugin({store}) {
|
||||||
store.$subscribe(() => { // 自动同步
|
store.$subscribe(() => { // 自动同步
|
||||||
// 在存储变化的时候执行
|
// 在存储变化的时候执行
|
||||||
|
@ -19,15 +20,16 @@ export function shareStorePlugin({store}) {
|
||||||
function stateSync(store) {
|
function stateSync(store) {
|
||||||
const storeName = store.$id
|
const storeName = store.$id
|
||||||
const jsonStr = JSON.stringify(store.$state)
|
const jsonStr = JSON.stringify(store.$state)
|
||||||
|
// console.log('state-change', jsonStr, storeName)
|
||||||
// 通知主线程更新
|
// 通知主线程更新
|
||||||
ipcRenderer.invoke('pinia-state-change', storeName, jsonStr)
|
ipcRenderer?.invoke('pinia-state-change', storeName, jsonStr)
|
||||||
}
|
}
|
||||||
// 同步数据-接收主线程消息
|
// 同步数据-接收主线程消息
|
||||||
function stateChange(store) {
|
function stateChange(store) {
|
||||||
const storeName = store.$id
|
const storeName = store.$id
|
||||||
ipcRenderer.on('pinia-state-set', (e, sName, jsonStr) => {
|
ipcRenderer?.on('pinia-state-set', (e, sName, jsonStr) => {
|
||||||
if (sName == storeName) { // 更新对应数据
|
if (sName == storeName) { // 更新对应数据
|
||||||
console.log('state-set', jsonStr, sName)
|
// console.log('state-set', jsonStr, sName)
|
||||||
const curJson = JSON.stringify(store.$state) // 当前数据
|
const curJson = JSON.stringify(store.$state) // 当前数据
|
||||||
const isUp = curJson != jsonStr // 不同的时候才写入,不然会导致触发数据变化监听,导致死循环
|
const isUp = curJson != jsonStr // 不同的时候才写入,不然会导致触发数据变化监听,导致死循环
|
||||||
if (!isUp) return
|
if (!isUp) return
|
||||||
|
|
|
@ -6,14 +6,17 @@
|
||||||
// Remote.app.getAppPath() E:\njys-work\AIx_Smarttalk\dist\win-unpacked\resources\app.asar
|
// Remote.app.getAppPath() E:\njys-work\AIx_Smarttalk\dist\win-unpacked\resources\app.asar
|
||||||
// path.join(__dirname) 根目录 E:\njys-work\AIx_Smarttalk\dist\win-unpacked\resources\app.asar\out\renderer
|
// path.join(__dirname) 根目录 E:\njys-work\AIx_Smarttalk\dist\win-unpacked\resources\app.asar\out\renderer
|
||||||
|
|
||||||
const path = require('path')
|
const isNode = typeof require !== 'undefined' // 是否支持node函数
|
||||||
const Remote = require('@electron/remote')
|
const path = isNode?require('path'):{}
|
||||||
const { ipcRenderer } = require('electron')
|
const Remote = isNode?require('@electron/remote'):{}
|
||||||
|
const { ipcRenderer } = isNode?require('electron'):window.electron || {}
|
||||||
|
|
||||||
// 常用变量
|
// 常用变量
|
||||||
const BaseUrl = process.env['ELECTRON_RENDERER_URL']+'/#'
|
const BaseUrl = isNode?process.env['ELECTRON_RENDERER_URL']+'/#':''
|
||||||
const isDev = process.env.NODE_ENV !== 'production'
|
const isDev = isNode?process.env.NODE_ENV !== 'production':''
|
||||||
|
|
||||||
|
// 暴露Remote中的属性
|
||||||
|
export const ipcMain = Remote?.ipcMain || {}
|
||||||
/**
|
/**
|
||||||
* 获取静态资源,开发和生产环境
|
* 获取静态资源,开发和生产环境
|
||||||
* @param {*} url
|
* @param {*} url
|
||||||
|
@ -39,15 +42,32 @@ export const getStaticUrl = (url = '', type = 'app', exitPath = '', isFile = fal
|
||||||
* url:路由地址,width:窗口宽度,height:窗口高度,option:自定义选项
|
* url:路由地址,width:窗口宽度,height:窗口高度,option:自定义选项
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function ipcMsgSend(key, data) {
|
export function ipcMsgSend(key, data, type) {
|
||||||
return new Promise((resolve) => {
|
if (type == 'old') {
|
||||||
// 返回结果-监听
|
return new Promise((resolve) => {
|
||||||
ipcRenderer.once(`${key}-reply`, (e, res) => {
|
// 返回结果-监听
|
||||||
resolve(res)
|
ipcRenderer?.once(`${key}-reply`, (e, res) => {
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
// 发送消息
|
||||||
|
ipcRenderer?.send(key, data)
|
||||||
})
|
})
|
||||||
// 发送消息
|
} else if (type == 'send') { // 单独发送
|
||||||
ipcRenderer.send(key, data)
|
ipcRenderer?.send(key, data)
|
||||||
})
|
} else { // 新版本-默认
|
||||||
|
return ipcRenderer?.invoke(key, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @description 封装ipcRenderer事件监听
|
||||||
|
* @param {*} fn on once handle invoke
|
||||||
|
* @param {*} key
|
||||||
|
* @param {Function} cb 回调函数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function ipcHandle(fn,key, cb) {
|
||||||
|
return ipcRenderer[fn](key, cb)
|
||||||
|
// return ipcRenderer?.[fn]?.(key, cb)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 创建-窗口 调用该方法
|
* 创建-窗口 调用该方法
|
||||||
|
@ -89,6 +109,7 @@ export const createWindow = async (type, data) => {
|
||||||
resizable: true, // 禁止窗口大小缩放
|
resizable: true, // 禁止窗口大小缩放
|
||||||
alwaysOnTop: false, // 窗口是否总是显示在其他窗口之前
|
alwaysOnTop: false, // 窗口是否总是显示在其他窗口之前
|
||||||
}
|
}
|
||||||
|
data.isConsole = true // 是否开启控制台
|
||||||
data.option = {...defOption, ...option}
|
data.option = {...defOption, ...option}
|
||||||
const win = await toolWindow(data)
|
const win = await toolWindow(data)
|
||||||
win.type = type // 唯一标识
|
win.type = type // 唯一标识
|
||||||
|
@ -146,7 +167,7 @@ export function toolWindow({url, isConsole, option={}}) {
|
||||||
// 内部监听器-是否打印
|
// 内部监听器-是否打印
|
||||||
if (!!isConsole) {
|
if (!!isConsole) {
|
||||||
win.webContents.on('console-message', (e,leve,m,lin,s) => {
|
win.webContents.on('console-message', (e,leve,m,lin,s) => {
|
||||||
console.log(m)
|
console.log(`[${win.type}]`,m)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -174,13 +195,17 @@ const eventHandles = (type, win) => {
|
||||||
case 'tool-sphere': { // 创建-悬浮球
|
case 'tool-sphere': { // 创建-悬浮球
|
||||||
// 监听设置穿透
|
// 监听设置穿透
|
||||||
const setIgnore = (_, ignore) => {win.setIgnoreMouseEvents(ignore, {forward: true})}
|
const setIgnore = (_, ignore) => {win.setIgnoreMouseEvents(ignore, {forward: true})}
|
||||||
Remote.ipcMain.on('tool-sphere:set:ignore', setIgnore)
|
Remote.ipcMain.handle('tool-sphere:set:ignore', setIgnore) // 异步
|
||||||
// 关闭窗口
|
// 关闭窗口
|
||||||
Remote.ipcMain.once('tool-sphere:close', () => { win&&win.destroy() })
|
Remote.ipcMain.once('tool-sphere:close', () => { win&&win.destroy() })
|
||||||
// 放大监听-测试
|
// 放大监听-测试
|
||||||
Remote.ipcMain.once('maximize-window', () => {win&&win.destroy()})
|
Remote.ipcMain.once('maximize-window', () => {win&&win.destroy()})
|
||||||
const on = {
|
const on = {
|
||||||
onClosed: () => {Remote.ipcMain.off('tool-sphere:set:ignore', setIgnore)}
|
onClosed: () => {
|
||||||
|
Remote.ipcMain.removeHandler('tool-sphere:set:ignore', setIgnore)
|
||||||
|
Remote.ipcMain.removeHandler('tool-sphere:reset')
|
||||||
|
// Remote.ipcMain.removeAllListeners() // 移除所有监听事件
|
||||||
|
}
|
||||||
}
|
}
|
||||||
publicMethods(on) // 加载公共方法
|
publicMethods(on) // 加载公共方法
|
||||||
break}
|
break}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {ref,defineProps,defineEmits} from "vue";
|
import {ref} from "vue";
|
||||||
const activeIndex = ref('0')
|
const activeIndex = ref('0')
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
classList:{
|
classList:{
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--选择学科-->
|
<!--选择学科-->
|
||||||
<SelectSubject v-model="isSubject" @onSuccess="successEditSubject" />
|
<SelectSubject v-model="isSubject" :loginData="loginForm" @onSuccess="successEditSubject"/>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, reactive, ref } from 'vue'
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
|
@ -35,7 +35,7 @@ import leftBg2 from '@/assets/images/login/left-bg2.png'
|
||||||
import WindowTools from '@/components/window-tools/index.vue'
|
import WindowTools from '@/components/window-tools/index.vue'
|
||||||
import SelectSubject from '@/components/select-subject/index.vue'
|
import SelectSubject from '@/components/select-subject/index.vue'
|
||||||
|
|
||||||
const { BrowserWindow, session } = require('@electron/remote')
|
const { session } = require('@electron/remote')
|
||||||
|
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
const formRef = ref()
|
const formRef = ref()
|
||||||
|
@ -48,6 +48,7 @@ const loginForm = reactive({
|
||||||
password: '',
|
password: '',
|
||||||
rememberMe: false
|
rememberMe: false
|
||||||
})
|
})
|
||||||
|
|
||||||
//表单规则
|
//表单规则
|
||||||
const rules = reactive({
|
const rules = reactive({
|
||||||
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
||||||
|
|
|
@ -40,7 +40,7 @@ const handleMode = (newVal, oldVal) => {
|
||||||
FabricVue.handleMode(TYPES.ActionMode.DRAW)
|
FabricVue.handleMode(TYPES.ActionMode.DRAW)
|
||||||
FabricVue.canvas.freeDrawingCursor = 'default'
|
FabricVue.canvas.freeDrawingCursor = 'default'
|
||||||
break
|
break
|
||||||
case 'eraser': // 板擦模式
|
case 'erase': // 板擦模式
|
||||||
FabricVue.handleMode(TYPES.ActionMode.ERASE)
|
FabricVue.handleMode(TYPES.ActionMode.ERASE)
|
||||||
break
|
break
|
||||||
case 'clear': // 清空画布
|
case 'clear': // 清空画布
|
||||||
|
@ -54,7 +54,7 @@ const handleMode = (newVal, oldVal) => {
|
||||||
}
|
}
|
||||||
// 监听
|
// 监听
|
||||||
watch(() => props.modelValue, (newVal, oldVal) => {
|
watch(() => props.modelValue, (newVal, oldVal) => {
|
||||||
console.log(newVal, oldVal)
|
// console.log(newVal, oldVal)
|
||||||
handleMode(newVal, oldVal)
|
handleMode(newVal, oldVal)
|
||||||
})
|
})
|
||||||
// 暴露属性方法
|
// 暴露属性方法
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
<template>
|
||||||
|
<div class="warp" ref="btnRef">
|
||||||
|
<slot name="start"></slot>
|
||||||
|
<!-- 工具按钮 -->
|
||||||
|
<el-space direction="vertical">
|
||||||
|
<template v-for="(item,index) in list">
|
||||||
|
<slot :name="item.prop" :item="item" :index="index">
|
||||||
|
<div class="c-btn flex flex-col items-center gap-2 p-2" @click.stop="clickHandel(item,$event)">
|
||||||
|
<i class="iconfont" :class="item.icon" :style="item.style" />
|
||||||
|
<span>{{item.label||item.text||item.name}}</span>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
<slot name="append"></slot>
|
||||||
|
</el-space>
|
||||||
|
<slot name="end"></slot>
|
||||||
|
<!-- 内容部分 -->
|
||||||
|
<transition name="el-fade-in">
|
||||||
|
<div class="c-popover" :style="`--top: ${topPos}px;--height:${hPost}px;`" v-show="isVisible">
|
||||||
|
<div class="content">{{activeObj}}</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { computed, defineProps, ref, reactive, watchEffect, onMounted } from 'vue'
|
||||||
|
// 功能说明:侧边-工具栏
|
||||||
|
const colors = ['#00f389', '#ff7f00', '#ffff00', '#409EFF', '#00baff', '#13b189', '#F56C6C']
|
||||||
|
const emit = defineEmits(['update:modelValue','change'])
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: { // 是否显示
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
data: { // 数据
|
||||||
|
type: Array,
|
||||||
|
default: () => [
|
||||||
|
{ label: '资源', prop: 'resource', icon: 'icon-hudong' },
|
||||||
|
{ label: '互动', prop: 'interact', icon: 'icon-hudong' },
|
||||||
|
{ label: '窗口', prop: 'win', icon: 'icon-hudong' },
|
||||||
|
{ label: '下课', prop: 'over', icon: 'icon-hudong' },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const isVisible = ref(false) // 是否显示内容
|
||||||
|
const activeObj = ref(null) // 当前激活的按钮
|
||||||
|
const btnRef = ref(null) // 按钮元素-ref
|
||||||
|
const topPos = ref(30) // 顶部距离-内容的距离
|
||||||
|
const hPost = ref(0) // 顶部距离-内容的距离
|
||||||
|
let posBtnAll = {} // 存储位置
|
||||||
|
// === 计算属性 ===
|
||||||
|
const list = computed(() => props.data.map((o,i) => {
|
||||||
|
o.style = getStyle(o.style, i)
|
||||||
|
return o
|
||||||
|
}))
|
||||||
|
onMounted(() => {
|
||||||
|
posBtnAll = btnRef.value.getBoundingClientRect()
|
||||||
|
hPost.value = posBtnAll.height
|
||||||
|
})
|
||||||
|
// === 方法 ===
|
||||||
|
// 获取颜色索引
|
||||||
|
const getIndex = i => i % colors.length
|
||||||
|
// 获取样式
|
||||||
|
const getStyle = (style,index) => {
|
||||||
|
const color = colors[getIndex(index)]
|
||||||
|
if (!style) return {color}
|
||||||
|
else {
|
||||||
|
if (typeof style === 'object') return {...style, color}
|
||||||
|
return `${style}${style.endsWith(';')?'':';'}color:${color};`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 事件
|
||||||
|
const clickHandel = (o, e) => {
|
||||||
|
const node = e.target.parentNode.getBoundingClientRect()
|
||||||
|
const isColse = activeObj.value && activeObj.value.prop === o.prop && isVisible.value
|
||||||
|
isVisible.value = !isColse // 相同的按钮且打开状态,点击关闭
|
||||||
|
activeObj.value = o
|
||||||
|
const nodeH = parseInt(node.height / 2) // 高度的一半
|
||||||
|
topPos.value = parseInt(node.top) - posBtnAll.top + nodeH
|
||||||
|
emit('change', o)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.warp{
|
||||||
|
border: 1px solid;
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
right: 10px;
|
||||||
|
min-height: 40vh;
|
||||||
|
min-width: 4em;
|
||||||
|
border-radius: 4em;
|
||||||
|
background-color: #121212;
|
||||||
|
.el-space{margin: 20px 0;}
|
||||||
|
.c-btn{
|
||||||
|
color: #d9dce3;
|
||||||
|
cursor: pointer;
|
||||||
|
.iconfont{
|
||||||
|
font-size: 20px;
|
||||||
|
color: attr(color);
|
||||||
|
}
|
||||||
|
span{font-size: 12px;}
|
||||||
|
&:hover{
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #454545fa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.c-popover{
|
||||||
|
--top: 30px;
|
||||||
|
--height: 40vh;
|
||||||
|
position: fixed;
|
||||||
|
inset: 50% 75px auto auto;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
background-color: #121212;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
min-height: var(--height);
|
||||||
|
width: 30em;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
&:before{
|
||||||
|
content: "";
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background-color: #121212;
|
||||||
|
position: absolute;
|
||||||
|
right: -5px;
|
||||||
|
top: var(--top);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.content{
|
||||||
|
color: red;
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* 处理元素是否穿透-窗口
|
||||||
|
*/
|
||||||
|
import { ipcMsgSend } from '@/utils/tool'
|
||||||
|
class Ignore {
|
||||||
|
el // 绑定元素
|
||||||
|
binding // 绑定对象(参数)
|
||||||
|
value // 绑定值
|
||||||
|
isAuto // 是否自动控制
|
||||||
|
constructor(el, binding) {
|
||||||
|
this.el = el
|
||||||
|
this.binding = binding
|
||||||
|
this.value = binding.value
|
||||||
|
this.isAuto = !(this.value && this.value instanceof Boolean)
|
||||||
|
}
|
||||||
|
// 设置是否穿透
|
||||||
|
send(bool) {
|
||||||
|
ipcMsgSend('tool-sphere:set:ignore', bool)
|
||||||
|
}
|
||||||
|
// 监听元素移入移出,自动设置
|
||||||
|
mounted() {
|
||||||
|
this.el.addEventListener('mouseenter', e => { // 进入
|
||||||
|
this.send(false) // 元素不穿透,鼠标有效
|
||||||
|
this.changeHandle(e)
|
||||||
|
})
|
||||||
|
this.el.addEventListener('mouseleave', e => { // 离开
|
||||||
|
this.send(true) // 元素穿透,鼠标无效
|
||||||
|
this.changeHandle(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
changeHandle(e) {
|
||||||
|
const customEvent = new CustomEvent('ignore-mounted', {detail:{ignore: this, e}})
|
||||||
|
this.el.dispatchEvent(customEvent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
mounted(el, binding) {
|
||||||
|
const ignore = new Ignore(el, binding)
|
||||||
|
if (ignore.isAuto) { // 自动控制
|
||||||
|
ignore.mounted()
|
||||||
|
} else { // 手动设置
|
||||||
|
ignore.send(ignore.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="warp-all">
|
<div class="warp-all">
|
||||||
|
<!-- 画板 -->
|
||||||
<board-vue v-model="tabActive" v-show="isShow" ref="boardVueRef"></board-vue>
|
<board-vue v-model="tabActive" v-show="isShow" ref="boardVueRef"></board-vue>
|
||||||
|
<!-- 侧边工具栏 -->
|
||||||
|
<side-vue v-ignore></side-vue>
|
||||||
<!-- 底部工具栏 :style="dataPos.style"-->
|
<!-- 底部工具栏 :style="dataPos.style"-->
|
||||||
<div class="tool-bottom-all"
|
<div class="tool-bottom-all" @mouseenter="mouseChange(0)" @mouseleave="mouseChange(1)">
|
||||||
@mouseenter="mouseChange(0)" @mouseleave="mouseChange(1)">
|
|
||||||
<div v-drag="{handle:'.tool-bottom-all', dragtime}"
|
<div v-drag="{handle:'.tool-bottom-all', dragtime}"
|
||||||
@v-drag-start="dragtime = Date.now()">
|
@v-drag-start="dragtime = Date.now()">
|
||||||
<div class="c-logo" @click="logoHandle" title="拖动 | 折叠 | 展开">
|
<div class="c-logo" @click="logoHandle" title="拖动 | 折叠 | 展开">
|
||||||
|
@ -15,7 +17,7 @@
|
||||||
@change="tabChange">
|
@change="tabChange">
|
||||||
<template #default="{item}">
|
<template #default="{item}">
|
||||||
<div class="c-btn flex flex-col items-center gap-2 p-2">
|
<div class="c-btn flex flex-col items-center gap-2 p-2">
|
||||||
<i class="iconfont" :class="item.icon" :style="item.style"></i>
|
<i class="iconfont" :class="item.icon" :style="item.style" />
|
||||||
<span>{{item.label}}</span>
|
<span>{{item.label}}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -29,54 +31,39 @@
|
||||||
// 功能说明:electron 悬浮球
|
// 功能说明:electron 悬浮球
|
||||||
import { onMounted, ref, reactive, watchEffect } from 'vue'
|
import { onMounted, ref, reactive, watchEffect } from 'vue'
|
||||||
import logo from '@root/resources/icon.png' // logo
|
import logo from '@root/resources/icon.png' // logo
|
||||||
import boardVue from './components/board.vue' // 画板
|
import boardVue from './components/board.vue' // 画板-子组件
|
||||||
|
import sideVue from './components/side.vue' // 画板-子组件
|
||||||
import vDrag from './directive/drag' // 自定义指令-拖拽
|
import vDrag from './directive/drag' // 自定义指令-拖拽
|
||||||
|
import vIgnore from './directive/ignore' // 自定义指令-穿透
|
||||||
import { useToolState } from '@/store/modules/tool'
|
import { useToolState } from '@/store/modules/tool'
|
||||||
const { ipcRenderer } = require('electron') // app使用
|
import { ipcMsgSend, ipcHandle, ipcMain } from '@/utils/tool' // 相关工具
|
||||||
// const ipcRenderer = { send: () => {} } // 网页测试使用
|
import {FabricVue, TYPES} from '@/plugins/fabric'
|
||||||
const tabActive = ref('select') // 工具栏当前选中项
|
const tabActive = ref('select') // 工具栏当前选中项
|
||||||
const isFold = ref(false) // 折叠工具栏
|
const isFold = ref(false) // 折叠工具栏
|
||||||
const isDrag = ref(false) // 开始拖拽
|
const isDrag = ref(false) // 开始拖拽
|
||||||
const dragtime = ref(0) // 拖拽时间-计算点击还是拖动
|
const dragtime = ref(0) // 拖拽时间-计算点击还是拖动
|
||||||
const isShow = ref(false)
|
const isShow = ref(false) // 是否显示-画板
|
||||||
const toolStore = useToolState()
|
const toolStore = useToolState() // 状态管理
|
||||||
const boardVueRef=ref(null) // 画板
|
const boardVueRef=ref(null) // 画板ref
|
||||||
const btnList = [ // 工具栏按钮列表
|
const btnList = [ // 工具栏按钮列表
|
||||||
{ label: '选择', value: 'select', icon: 'icon-mouse' },
|
{ label: '选择', value: 'select', icon: 'icon-mouse' },
|
||||||
{ label: '画笔', value: 'brush', icon: 'icon-huabi' },
|
{ label: '画笔', value: 'brush', icon: 'icon-huabi' },
|
||||||
{ label: '板擦', value: 'eraser', icon: 'icon-xiangpica' },
|
{ label: '板擦', value: 'erase', icon: 'icon-xiangpica' },
|
||||||
{ label: '清除', value: 'clear', icon: 'icon-xiangpica', style: 'color: #ccc' },
|
{ label: '清除', value: 'clear', icon: 'icon-xiangpica', style: 'color: #ccc' },
|
||||||
// { label: '互动', value: 'interact', icon: 'icon-hudong' },
|
// { label: '互动', value: 'interact', icon: 'icon-hudong' },
|
||||||
// { label: '聚焦', value: 'focus', icon: 'icon-jujiao' },
|
// { label: '聚焦', value: 'focus', icon: 'icon-jujiao' },
|
||||||
// { label: '更多', value: 'more', icon: 'icon-xiazai9' },
|
// { label: '更多', value: 'more', icon: 'icon-xiazai9' },
|
||||||
]
|
]
|
||||||
onMounted(() => {
|
// 页面加载完毕
|
||||||
// isShow.value = toolStore.showBoardAll // 是否显示-画板
|
onMounted(async() => {
|
||||||
// console.log('xxx: ', toolStore.model)
|
resetStatus() // 开启重置状态-监听
|
||||||
// setTimeout(() => {
|
|
||||||
// toolStore.windowState.test = '测试成功'
|
|
||||||
// }, 2000);
|
|
||||||
})
|
})
|
||||||
|
// const test = (e) => { console.log('test', e) }
|
||||||
// ==== 方法 ===
|
// ==== 方法 ===
|
||||||
const tabChange = (val) => { // 切换tab-change
|
const tabChange = (val) => { // 切换tab-change
|
||||||
if(!toolStore.isPdfWin) toolStore.showBoardAll = true
|
const bool = !toolStore.isPdfWin && !toolStore.showBoardAll
|
||||||
switch (val) {
|
if(bool) toolStore.showBoardAll = true
|
||||||
case 'brush': // 画笔
|
// ipcMsgSend('tool-sphere:close')
|
||||||
break
|
|
||||||
case 'eraser': // 板擦
|
|
||||||
break
|
|
||||||
case 'interact':
|
|
||||||
break
|
|
||||||
case 'focus':
|
|
||||||
break
|
|
||||||
case 'more':
|
|
||||||
break
|
|
||||||
case 'close':
|
|
||||||
ipcRenderer.send('tool-sphere:close')
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
toolStore.model = val // 存储当前tab
|
toolStore.model = val // 存储当前tab
|
||||||
}
|
}
|
||||||
const logoHandle = (e,t) => { // logo 点击-事件 折叠|展开
|
const logoHandle = (e,t) => { // logo 点击-事件 折叠|展开
|
||||||
|
@ -84,7 +71,6 @@ const logoHandle = (e,t) => { // logo 点击-事件 折叠|展开
|
||||||
isFold.value = !isFold.value
|
isFold.value = !isFold.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mouseChange = (bool) => { // 鼠标移入工具栏 是否穿透
|
const mouseChange = (bool) => { // 鼠标移入工具栏 是否穿透
|
||||||
let resBool = false
|
let resBool = false
|
||||||
if (tabActive.value == 'select') resBool = !!bool
|
if (tabActive.value == 'select') resBool = !!bool
|
||||||
|
@ -92,20 +78,19 @@ const mouseChange = (bool) => { // 鼠标移入工具栏 是否穿透
|
||||||
setIgnore(resBool)
|
setIgnore(resBool)
|
||||||
}
|
}
|
||||||
const setIgnore = (bool) => { // 忽略鼠标穿透
|
const setIgnore = (bool) => { // 忽略鼠标穿透
|
||||||
ipcRenderer.send('tool-sphere:set:ignore', bool)
|
ipcMsgSend('tool-sphere:set:ignore', bool)
|
||||||
}
|
}
|
||||||
// // 监听画板状态
|
const resetStatus = () => { // 重置状态
|
||||||
// ipcRenderer.send('tool-sphere:reset', () => {
|
ipcMain.handle('tool-sphere:reset', () => {
|
||||||
|
FabricVue.handleMode(tabActive.value)
|
||||||
// })
|
setTimeout(() => { mouseChange(1) }, 500)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
watchEffect(() => { // 监听
|
watchEffect(() => { // 监听
|
||||||
isShow.value = !toolStore.isPdfWin&&toolStore.showBoardAll // 是否显示-画板
|
// 不同的时候, 更新值: 是否显示-画板
|
||||||
if(!toolStore.isPdfWin && toolStore.showBoardAll){ //恢复进入页面前的状态
|
const show = !toolStore.isPdfWin && toolStore.showBoardAll
|
||||||
// setTimeout(() => {
|
if (show != isShow.value) isShow.value = show
|
||||||
boardVueRef.value.handleMode(tabActive.value)
|
|
||||||
setIgnore(false)
|
|
||||||
// },0)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue