Compare commits
18 Commits
eb481e265b
...
a6bda302af
Author | SHA1 | Date |
---|---|---|
lyc | a6bda302af | |
zhengdegang | 411ef757e2 | |
zdg | 0201385e75 | |
zdg | ea9af1440e | |
zdg | b4c2751e8c | |
yangws | c5257b760a | |
yangws | 22239090ea | |
zdg | 1d808950b5 | |
zhengdegang | cb0d60b93e | |
zdg | d65af70a34 | |
zdg | 3f4e9c35b0 | |
zhengdegang | a133c322f3 | |
zdg | b5d41050ae | |
zdg | fa77c6cc6b | |
lyc | ff97a2bef6 | |
zhengdegang | 2ae200cc9e | |
zdg | 177df96d69 | |
zdg | 571bfc98f7 |
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "aix-win",
|
"name": "aix-win",
|
||||||
"version": "1.1.1",
|
"version": "1.1.6",
|
||||||
"description": "An Electron application with Vue",
|
"description": "An Electron application with Vue",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "example.com",
|
"author": "example.com",
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
|
@ -3,15 +3,17 @@ 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 Logger from './logger' // 日志封装
|
||||||
import chat from './chat' // chat封装
|
import chat from './chat' // chat封装
|
||||||
import Store from './store' // Store封装
|
import Store from './store' // Store封装
|
||||||
import updateInit from './update'
|
import updateInit from './update'
|
||||||
|
|
||||||
// 代理 electron/remote
|
// 代理 electron/remote
|
||||||
// 第一步:引入remote
|
// 第一步:引入remote
|
||||||
import remote from '@electron/remote/main'
|
import remote from '@electron/remote/main'
|
||||||
// 第二步: 初始化remote
|
// 第二步: 初始化remote
|
||||||
remote.initialize()
|
remote.initialize()
|
||||||
|
// 日志配置-初始化(日志直接绑定到console上)
|
||||||
|
if(!is.dev) Logger.initialize()
|
||||||
// 持久化数据-初始化
|
// 持久化数据-初始化
|
||||||
Store.initialize()
|
Store.initialize()
|
||||||
|
|
||||||
|
@ -153,6 +155,7 @@ async function createLinkWin(data) {
|
||||||
|
|
||||||
// 初始化完成
|
// 初始化完成
|
||||||
app.on('ready', () => {
|
app.on('ready', () => {
|
||||||
|
appWatchError() // 监听app错误
|
||||||
process.env.LANG = 'en_US.UTF-8'
|
process.env.LANG = 'en_US.UTF-8'
|
||||||
// 设置应用程序用户模型标识符
|
// 设置应用程序用户模型标识符
|
||||||
electronApp.setAppUserModelId('com.electron')
|
electronApp.setAppUserModelId('com.electron')
|
||||||
|
@ -259,3 +262,34 @@ function handleAll() {
|
||||||
win.webContents.send('pinia-state-set', storeName, jsonStr)
|
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)}`)
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
* @description 日志配置
|
||||||
|
* @author zdg
|
||||||
|
* @date 2021-07-05 14:07:01
|
||||||
|
*/
|
||||||
|
// import log from 'electron-log'
|
||||||
|
import log from 'electron-log/main'
|
||||||
|
import { app } from 'electron'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
// 关闭控制台打印
|
||||||
|
// 日志控制台等级,默认值:false
|
||||||
|
log.transports.console.level = false
|
||||||
|
// log.transports.console.level = 'info'
|
||||||
|
// 日志文件等级,默认值:false
|
||||||
|
log.transports.file.level = 'info'
|
||||||
|
// 日志文件名,默认:main.log
|
||||||
|
// log.transports.file.fileName = 'main.log';
|
||||||
|
// 日志大小,默认:1048576(1M),达到最大上限后,备份文件并重命名为:main.old.log,有且仅有一个备份文件
|
||||||
|
log.transports.file.maxSize = 10 * 1024 * 1024; // 文件最大不超过 10M
|
||||||
|
// 自定义日志文件滚动策略
|
||||||
|
log.transports.file.rollSize = 10 * 1024 * 1024; // 10MB
|
||||||
|
// 日志格式,默认:[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}]{scope} {text}
|
||||||
|
log.transports.file.format = '[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}]{scope} {text}'
|
||||||
|
let date = new Date()
|
||||||
|
let dateStr = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate()
|
||||||
|
// 文件位置及命名方式
|
||||||
|
// 默认位置为:C:\Users\[user]\AppData\Roaming\[appname]\electron_log\
|
||||||
|
// 文件名为:年-月-日.log
|
||||||
|
// 自定义文件保存位置为安装目录下 \log\年-月-日.log
|
||||||
|
// log.transports.file.resolvePathFn = () => 'logs\\' + dateStr+ '.log';
|
||||||
|
log.transports.file.resolvePathFn = () => path.join(app.getPath('userData'), `logs/${dateStr}.log`)
|
||||||
|
|
||||||
|
// 有六个日志级别error, warn, info, verbose, debug, silly。默认是silly
|
||||||
|
export const logger = {
|
||||||
|
error: (...args) => log.error(...args),
|
||||||
|
warn: (...args) => log.warn(...args),
|
||||||
|
info: (...args) => log.info(...args),
|
||||||
|
verbose: (...args) => log.verbose(...args),
|
||||||
|
debug: (...args) => log.debug(...args),
|
||||||
|
silly: (...args) => log.silly(...args)
|
||||||
|
}
|
||||||
|
export function initialize(bool = true, type = 'all') {
|
||||||
|
log.initialize() // 为渲染器进行初始化
|
||||||
|
if (bool) { // 是否替换默认的console
|
||||||
|
if (type == 'all') Object.assign(console, log.functions)
|
||||||
|
else { // 替换指定类型
|
||||||
|
console[type] = log[type]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default { initialize }
|
|
@ -8,6 +8,7 @@ Store.initRenderer()
|
||||||
|
|
||||||
// 默认共享数据
|
// 默认共享数据
|
||||||
const defaultData = {
|
const defaultData = {
|
||||||
|
session: { // 缓存(临时sessionStorage)
|
||||||
model: 'select', // 悬浮球-当前模式
|
model: 'select', // 悬浮球-当前模式
|
||||||
showBoardAll: false, // 全屏画板-是否显示
|
showBoardAll: false, // 全屏画板-是否显示
|
||||||
isPdfWin: false, // pdf窗口是否打开
|
isPdfWin: false, // pdf窗口是否打开
|
||||||
|
@ -16,17 +17,45 @@ const defaultData = {
|
||||||
data: {}, // 当前教材节点 (包含当前教材 单元)
|
data: {}, // 当前教材节点 (包含当前教材 单元)
|
||||||
querySearch: {} // 查询资源所需参数
|
querySearch: {} // 查询资源所需参数
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
local: { // 本地(永久localStorage)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
export function initialize(){
|
export function initialize(){
|
||||||
const store = new Store({
|
// 缓存数据-sessionStore
|
||||||
name: 'cache-store', // 存储文件名
|
const sessionStore = new Store({
|
||||||
|
name: 'session-store', // 存储文件名
|
||||||
fileExtension: 'ini', // 文件后缀名
|
fileExtension: 'ini', // 文件后缀名
|
||||||
encryptionKey: 'Eihrjwi7h104h2Kub423' // 数据加密-防止用户直接改配置
|
encryptionKey: 'BvPLmgCC4DSIG0KkTec5', // 数据加密-防止用户直接改配置
|
||||||
|
beforeEachMigration: (store, context) => { // 版本迁移回调
|
||||||
|
console.log(`[session-store] 迁移从 ${context.fromVersion} → ${context.toVersion}`);
|
||||||
|
},
|
||||||
|
migrations: { // 版本变化
|
||||||
|
'0.0.0': store => {
|
||||||
|
// store.set('debugPhase', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
store.clear() // 先清除-所有缓存数据
|
sessionStore.clear() // 先清除-所有缓存数据
|
||||||
store.set(defaultData) // 初始化-默认数据
|
sessionStore.set(defaultData.session) // 初始化-默认数据
|
||||||
return store
|
|
||||||
|
// 缓存数据-localStore
|
||||||
|
const localStore = new Store({
|
||||||
|
name: 'local-store', // 存储文件名
|
||||||
|
fileExtension: 'ini', // 文件后缀名
|
||||||
|
encryptionKey: '6CyoHQmUaPmLzvVsh', // 数据加密-防止用户直接改配置
|
||||||
|
beforeEachMigration: (store, context) => { // 版本迁移回调
|
||||||
|
console.log(`[local-store] 迁移从 ${context.fromVersion} → ${context.toVersion}`);
|
||||||
|
},
|
||||||
|
migrations: { // 版本变化
|
||||||
|
'0.0.0': store => {
|
||||||
|
// store.set('debugPhase', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
localStore.set(defaultData.local) // 初始化-默认数据
|
||||||
|
return {sessionStore, localStore}
|
||||||
}
|
}
|
||||||
export default { initialize }
|
export default { initialize }
|
|
@ -383,16 +383,7 @@ defineExpose({
|
||||||
savaDataStore
|
savaDataStore
|
||||||
})
|
})
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
setTimeout(() => {
|
|
||||||
console.log(toolState,'监听')
|
|
||||||
|
|
||||||
}, 300)
|
|
||||||
if(toolState.isPdfWin){
|
if(toolState.isPdfWin){
|
||||||
// if(toolState.isToolWin){
|
|
||||||
// ispointer.value=false
|
|
||||||
// }else{
|
|
||||||
// ispointer.value=true
|
|
||||||
// }
|
|
||||||
watchToolState() //监听工具栏
|
watchToolState() //监听工具栏
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,10 +12,14 @@ import 'virtual:windi.css'
|
||||||
import { store } from '@/store'
|
import { store } from '@/store'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
|
import log from 'electron-log/renderer' // 渲染进程日志-文件记录
|
||||||
|
|
||||||
|
if(process.env.NODE_ENV != 'development') { // 非开发环境,将日志打印到日志文件
|
||||||
|
Object.assign(console, log.functions) // 渲染进程日志-控制台替换
|
||||||
|
}
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
|
|
||||||
app.use(router)
|
app.use(router)
|
||||||
.use(store)
|
.use(store)
|
||||||
.use(ElementPlus, { locale: zhLocale }).mount('#app')
|
.use(ElementPlus, { locale: zhLocale }).mount('#app')
|
|
@ -3,13 +3,14 @@
|
||||||
*/
|
*/
|
||||||
const isNode = typeof require !== 'undefined' // 是否支持node函数
|
const isNode = typeof require !== 'undefined' // 是否支持node函数
|
||||||
const { ipcRenderer } = isNode?require('electron'):{} // app使用
|
const { ipcRenderer } = isNode?require('electron'):{} // app使用
|
||||||
|
import { sessionStore } from '@/utils/tool'
|
||||||
// const Remote = isNode?require('@electron/remote'):{} // 远程模块
|
// const Remote = isNode?require('@electron/remote'):{} // 远程模块
|
||||||
export function shareStorePlugin({store}) {
|
export function shareStorePlugin({store}) {
|
||||||
store.$subscribe((mutation, state) => { // 自动同步
|
store.$subscribe((mutation, state) => { // 自动同步
|
||||||
// mutation 变量包含了变化前后的状态
|
// mutation 变量包含了变化前后的状态
|
||||||
// mutation.events: key newValue target oldValue oldTarget
|
// mutation.events: key newValue target oldValue oldTarget
|
||||||
// state 是变化后的状态
|
// state 是变化后的状态
|
||||||
// console.log('store.$subscribe', mutation)
|
// console.log('store.$subscribe', mutation, state, store)
|
||||||
// 在存储变化的时候执行
|
// 在存储变化的时候执行
|
||||||
// const storeName = store.$id
|
// const storeName = store.$id
|
||||||
const storeName = mutation.storeId
|
const storeName = mutation.storeId
|
||||||
|
@ -19,13 +20,15 @@ export function shareStorePlugin({store}) {
|
||||||
const { storeId: storeName, payload, events, type } = mutation // direct
|
const { storeId: storeName, payload, events, type } = mutation // direct
|
||||||
// if (!Object.keys(payload).length) return
|
// if (!Object.keys(payload).length) return
|
||||||
if (type != 'direct' || !events || Array.isArray(events) || !events.key) return
|
if (type != 'direct' || !events || Array.isArray(events) || !events.key) return
|
||||||
stateSync(storeName, events.key, events.newValue) // 需要同步
|
stateSync(storeName, events.key, events.newValue, state) // 需要同步
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 暴露方法-手动同步
|
// 暴露方法-手动同步
|
||||||
store.stateSync = (storeName, key, value) => {
|
store.stateSync = (storeName, key, value) => {
|
||||||
if (!storeName && !!key && !!value) stateSync(storeName, key, value)
|
const state = store.$state
|
||||||
else stateSyncAll(store)
|
if (!storeName && !!key && !!value) stateSync(storeName, key, value, state)
|
||||||
|
else stateSyncAll(store, state)
|
||||||
}
|
}
|
||||||
// 暴露方法-发送当前状态-新窗口
|
// 暴露方法-发送当前状态-新窗口
|
||||||
store.stateSyncInit = wid => stateSyncInit(wid, store)
|
store.stateSyncInit = wid => stateSyncInit(wid, store)
|
||||||
|
@ -34,14 +37,16 @@ export function shareStorePlugin({store}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同步数据-发送给主线程-单独
|
// 同步数据-发送给主线程-单独
|
||||||
function stateSync(storeName, key, value) {
|
function stateSync(storeName, key, value, state) {
|
||||||
// console.log('state-change', storeName, key, value)
|
// console.log('state-change', storeName, key, value)
|
||||||
try {
|
try {
|
||||||
let jsonStr = ''
|
const { data, keystr } = filterByKey(state, key, value)
|
||||||
if (typeof key === 'string') jsonStr = JSON.stringify({[key]:value})
|
const jsonStr = JSON.stringify(data) // 从新组装-json数据
|
||||||
else if (typeof value === 'object') jsonStr = JSON.stringify(key)
|
// 更新本地数据-session
|
||||||
|
sessionStore.set(keystr, value)
|
||||||
// 通知主线程更新
|
// 通知主线程更新
|
||||||
ipcRenderer?.invoke('pinia-state-change', storeName, jsonStr)
|
ipcRenderer?.invoke('pinia-state-change', storeName, jsonStr)
|
||||||
|
// console.log('======',keystr, data )
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('state-change-error', error)
|
console.log('state-change-error', error)
|
||||||
}
|
}
|
||||||
|
@ -95,3 +100,27 @@ const circularSafeStringify = (obj) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 过滤对象
|
||||||
|
const filterByKey = (obj, key, value) => {
|
||||||
|
let res = { data:{}, keystr:'' }
|
||||||
|
for (let k in obj) {
|
||||||
|
if (obj.hasOwnProperty(k)) {
|
||||||
|
const isEqual = JSON.stringify(obj[k]) === JSON.stringify(value) // 值是否相同
|
||||||
|
if (k === key && isEqual) {
|
||||||
|
// 如果匹配,则添加到新对象中
|
||||||
|
res.data[k] = obj[k];
|
||||||
|
res.keystr = k;
|
||||||
|
} else {
|
||||||
|
if (obj[k] !== null && typeof obj[k] === 'object') {
|
||||||
|
// 如果是对象,则递归处理
|
||||||
|
const {data, keystr} = filterByKey(obj[k], key, value)
|
||||||
|
res.data[k] = data
|
||||||
|
res.keystr = keystr ? `${k}.${keystr}`: key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
// 对象克隆
|
||||||
|
const objClone = (obj) => JSON.parse(JSON.stringify(obj))
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
* 工具类-窗口-状态管理
|
* 工具类-窗口-状态管理
|
||||||
*/
|
*/
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
import { sessionStore } from '@/utils/tool'
|
||||||
|
|
||||||
|
// 默认数据
|
||||||
|
const defData = sessionStore.store || {}
|
||||||
|
|
||||||
export const useToolState = defineStore('tool', {
|
export const useToolState = defineStore('tool', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
|
@ -12,7 +16,8 @@ export const useToolState = defineStore('tool', {
|
||||||
curSubjectNode: {
|
curSubjectNode: {
|
||||||
data: {}, // 当前教材节点 (包含当前教材 单元)
|
data: {}, // 当前教材节点 (包含当前教材 单元)
|
||||||
querySearch: {} // 查询资源所需参数
|
querySearch: {} // 查询资源所需参数
|
||||||
}
|
},
|
||||||
|
...defData // 默认数据-覆盖上面的配置(不要删除, 会导致新窗口-获取状态失败)
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,22 +11,31 @@ const path = isNode?require('path'):{}
|
||||||
const Remote = isNode?require('@electron/remote'):{}
|
const Remote = isNode?require('@electron/remote'):{}
|
||||||
const { ipcRenderer } = isNode?require('electron'):window.electron || {}
|
const { ipcRenderer } = isNode?require('electron'):window.electron || {}
|
||||||
const API = isNode?window.api:{} // preload-api
|
const API = isNode?window.api:{} // preload-api
|
||||||
import { useToolState } from '@/store/modules/tool' // 获取store状态
|
// import { useToolState } from '@/store/modules/tool' // 获取store状态
|
||||||
const Store = isNode?require('electron-store'):null // 持久化存储
|
const Store = isNode?require('electron-store'):null // 持久化存储
|
||||||
|
|
||||||
// 常用变量
|
// 常用变量
|
||||||
const BaseUrl = isNode?process.env['ELECTRON_RENDERER_URL']+'/#':''
|
const BaseUrl = isNode?process.env['ELECTRON_RENDERER_URL']+'/#':''
|
||||||
const isDev = isNode?process.env.NODE_ENV !== 'production':''
|
const isDev = isNode?process.env.NODE_ENV !== 'production':''
|
||||||
const toolState = useToolState() // 获取store状态
|
// const toolState = useToolState() // 获取store状态
|
||||||
|
|
||||||
// 暴露Remote中的属性
|
// 暴露Remote中的属性
|
||||||
export const ipcMain = Remote?.ipcMain || {}
|
export const ipcMain = Remote?.ipcMain || {}
|
||||||
// 暴露Store存储对象
|
|
||||||
export const store = Store ? new Store({
|
// 暴露sessionStore存储对象
|
||||||
name: 'cache-store', // 存储文件名
|
export const sessionStore = Store ? new Store({
|
||||||
|
name: 'session-store', // 存储文件名
|
||||||
fileExtension: 'ini', // 文件后缀名
|
fileExtension: 'ini', // 文件后缀名
|
||||||
encryptionKey: 'Eihrjwi7h104h2Kub423' // 数据加密-防止用户直接改配置
|
encryptionKey: 'BvPLmgCC4DSIG0KkTec5' // 数据加密-防止用户直接改配置
|
||||||
}) : {}
|
}) : {}
|
||||||
|
|
||||||
|
// 暴露localStore存储对象
|
||||||
|
export const localStore = Store ? new Store({
|
||||||
|
name: 'local-store', // 存储文件名
|
||||||
|
fileExtension: 'ini', // 文件后缀名
|
||||||
|
encryptionKey: '6CyoHQmUaPmLzvVsh' // 数据加密-防止用户直接改配置
|
||||||
|
}) : {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取静态资源,开发和生产环境
|
* 获取静态资源,开发和生产环境
|
||||||
* @param {*} url
|
* @param {*} url
|
||||||
|
@ -128,7 +137,7 @@ export const createWindow = async (type, data) => {
|
||||||
winPdf.restore();
|
winPdf.restore();
|
||||||
} else{
|
} else{
|
||||||
winPdf.focus();
|
winPdf.focus();
|
||||||
toolState.isPdfWin=true
|
// toolState.isPdfWin=true
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -195,9 +204,9 @@ export function toolWindow({url, isConsole, isWeb=true, option={}}) {
|
||||||
mainWin.once('closed', () => { win.destroy()})
|
mainWin.once('closed', () => { win.destroy()})
|
||||||
// 内部监听器
|
// 内部监听器
|
||||||
win.webContents.on('did-finish-load', () => {
|
win.webContents.on('did-finish-load', () => {
|
||||||
setTimeout(() => {
|
// setTimeout(() => {
|
||||||
toolState.stateSyncInit(win.id) // 同步状态
|
// toolState.stateSyncInit(win.id) // 同步状态
|
||||||
}, 200);
|
// }, 200);
|
||||||
})
|
})
|
||||||
// 内部监听器-是否打印
|
// 内部监听器-是否打印
|
||||||
if (!!isConsole) {
|
if (!!isConsole) {
|
||||||
|
|
|
@ -104,9 +104,12 @@ const switchPageMode = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
const isDev = process.env.NODE_ENV == 'development'
|
||||||
toolState.isPdfWin=true //设置打开pdf窗口
|
toolState.isPdfWin=true //设置打开pdf窗口
|
||||||
|
if (isDev)
|
||||||
|
pdfObj.pdfUrl = getStaticUrl('aaa.pdf', 'user', 'selfFile', true) //本地
|
||||||
|
else
|
||||||
pdfObj.pdfUrl = getStaticUrl(route.query.path, 'user', 'selfFile', true) //线上
|
pdfObj.pdfUrl = getStaticUrl(route.query.path, 'user', 'selfFile', true) //线上
|
||||||
// pdfObj.pdfUrl = getStaticUrl('aaa.pdf', 'user', 'selfFile', true) //本地
|
|
||||||
textbookId.value = route.query.textbookId
|
textbookId.value = route.query.textbookId
|
||||||
pdfObj.bookId=textbookId.value
|
pdfObj.bookId=textbookId.value
|
||||||
//初始化获取接口数据
|
//初始化获取接口数据
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<el-card style="width: 100%;height: 100%">
|
<el-card style="width: 100%;height: 100%">
|
||||||
<template #header>
|
<!-- <template #header>-->
|
||||||
<div class="card-header" style="text-align: left">
|
<!-- <div class="card-header" style="text-align: left">-->
|
||||||
<el-button type="primary" @click="addGroup">新建分组</el-button>
|
<!-- <el-button type="primary" @click="addGroup">新建分组</el-button>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</template>
|
<!-- </template>-->
|
||||||
<template v-if="groupList.length > 0">
|
<template v-if="groupList.length > 0">
|
||||||
<div style="font-size: 16px;font-weight: bold;color: #000;text-align: left;margin-bottom: 5px">可用分组</div>
|
<div style="font-size: 16px;font-weight: bold;color: #000;text-align: left;margin-bottom: 5px">可用分组</div>
|
||||||
<div class="groupList">
|
<div class="groupList">
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<el-card style="width: 100%;height: 100%">
|
<el-card style="width: 100%;height: 100%">
|
||||||
<template #header>
|
<!-- <template #header>-->
|
||||||
<div style="text-align: left">
|
<!-- <div style="text-align: left">-->
|
||||||
<el-button type="danger" @click="deleteClassRoom">删除班级</el-button>
|
<!-- <el-button type="danger" @click="deleteClassRoom">删除班级</el-button>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</template>
|
<!-- </template>-->
|
||||||
<el-descriptions :column="1">
|
<el-descriptions :column="1">
|
||||||
<el-descriptions-item label="班级名称">{{ classInfo.caption }}</el-descriptions-item>
|
<el-descriptions-item label="班级名称">{{ classInfo.caption }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="教师">
|
<el-descriptions-item label="教师">
|
||||||
|
|
|
@ -6,11 +6,12 @@
|
||||||
<div :style="{'max-height': (viewportHeight - 120) + 'px','overflow-y': 'auto'}">
|
<div :style="{'max-height': (viewportHeight - 120) + 'px','overflow-y': 'auto'}">
|
||||||
<Aside :menuItems="menuItems" :classList="classList" @handleSelect="handleSelect"></Aside>
|
<Aside :menuItems="menuItems" :classList="classList" @handleSelect="handleSelect"></Aside>
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<!-- 隐藏操作按钮-->
|
||||||
<div>
|
<!-- <template #footer>-->
|
||||||
<el-button @click="addClass" type="primary" :icon="Plus" >新增班级</el-button>
|
<!-- <div>-->
|
||||||
</div>
|
<!-- <el-button @click="addClass" type="primary" :icon="Plus" >新增班级</el-button>-->
|
||||||
</template>
|
<!-- </div>-->
|
||||||
|
<!-- </template>-->
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-aside>
|
</el-aside>
|
||||||
<el-main :style="{'min-height': (viewportHeight - 160) + 'px'}">
|
<el-main :style="{'min-height': (viewportHeight - 160) + 'px'}">
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
<el-card style="width: 100%;height: 100%;overflow-y: auto">
|
<el-card style="width: 100%;height: 100%;overflow-y: auto">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div style="text-align: left;display: flex;justify-content: space-between">
|
<div style="text-align: left;display: flex;justify-content: space-between">
|
||||||
<div>
|
<!-- <div>-->
|
||||||
<el-button type="primary" @click="addStudent(0)">新增学生</el-button>
|
<!-- <el-button type="primary" @click="addStudent(0)">新增学生</el-button>-->
|
||||||
<el-button type="primary" @click="importStudent()">导入学生</el-button>
|
<!-- <el-button type="primary" @click="importStudent()">导入学生</el-button>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<el-text class="mx-1">点击学生头像查看学生信息</el-text>
|
<el-text class="mx-1">点击学生头像查看学生信息</el-text>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -54,27 +54,27 @@
|
||||||
<el-form-item label="电话" prop="parentmobile">
|
<el-form-item label="电话" prop="parentmobile">
|
||||||
<el-input v-model="studentForm.parentmobile" placeholder="请输入电话" style="width: 50%"/>
|
<el-input v-model="studentForm.parentmobile" placeholder="请输入电话" style="width: 50%"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div>
|
<!-- <div>-->
|
||||||
<el-row :gutter="4">
|
<!-- <el-row :gutter="4">-->
|
||||||
<el-col :span="12">
|
<!-- <el-col :span="12">-->
|
||||||
<el-form-item label-width="100px" label="平台登录账号">
|
<!-- <el-form-item label-width="100px" label="平台登录账号">-->
|
||||||
系统自动创建
|
<!-- 系统自动创建-->
|
||||||
</el-form-item>
|
<!-- </el-form-item>-->
|
||||||
</el-col>
|
<!-- </el-col>-->
|
||||||
<el-col :span="12">
|
<!-- <el-col :span="12">-->
|
||||||
<el-form-item label-width="100px" label="平台登录密码">
|
<!-- <el-form-item label-width="100px" label="平台登录密码">-->
|
||||||
系统自动创建,默认为123123
|
<!-- 系统自动创建,默认为123123-->
|
||||||
</el-form-item>
|
<!-- </el-form-item>-->
|
||||||
</el-col>
|
<!-- </el-col>-->
|
||||||
</el-row>
|
<!-- </el-row>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<!-- <template #footer>-->
|
||||||
<el-button type="warning" v-show="studentForm.id > 0" @click="delStudent(1)">移出班级</el-button>
|
<!-- <el-button type="warning" v-show="studentForm.id > 0" @click="delStudent(1)">移出班级</el-button>-->
|
||||||
<el-button type="danger" v-show="studentForm.id > 0 && studentForm.editoruserid == userStore.userId" @click="delStudent(2)">删除学生</el-button>
|
<!-- <el-button type="danger" v-show="studentForm.id > 0 && studentForm.editoruserid == userStore.userId" @click="delStudent(2)">删除学生</el-button>-->
|
||||||
<el-button @click="studentVisible = false">取 消</el-button>
|
<!-- <el-button @click="studentVisible = false">取 消</el-button>-->
|
||||||
<el-button type="primary" @click="btnStudentSave">确 定</el-button>
|
<!-- <el-button type="primary" @click="btnStudentSave">确 定</el-button>-->
|
||||||
</template>
|
<!-- </template>-->
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!-- 学生导入-->
|
<!-- 学生导入-->
|
||||||
<el-dialog title="学生导入" v-model="importVisiable" :width="600" append-to-body>
|
<el-dialog title="学生导入" v-model="importVisiable" :width="600" append-to-body>
|
||||||
|
|
|
@ -144,12 +144,13 @@ import { parseCataByNode, creatPPT, asyncLocalFile } from '@/utils/talkFile'
|
||||||
import FileOperBatch from '@/views/prepare/container/file-oper-batch.vue'
|
import FileOperBatch from '@/views/prepare/container/file-oper-batch.vue'
|
||||||
import SetHomework from '@/components/set-homework/index.vue'
|
import SetHomework from '@/components/set-homework/index.vue'
|
||||||
import outLink from '@/utils/linkConfig'
|
import outLink from '@/utils/linkConfig'
|
||||||
import { createWindow } from '@/utils/tool'
|
import { createWindow, sessionStore } from '@/utils/tool'
|
||||||
import { cloneDeep } from 'lodash'
|
import { cloneDeep } from 'lodash'
|
||||||
import { delClasswork } from '@/api/teaching/classwork'
|
import { delClasswork } from '@/api/teaching/classwork'
|
||||||
import { getSelfReserv, startClass } from '@/api/classManage'
|
import { getSelfReserv, startClass } from '@/api/classManage'
|
||||||
import { useGetHomework } from '@/hooks/useGetHomework'
|
import { useGetHomework } from '@/hooks/useGetHomework'
|
||||||
const toolStore = useToolState()
|
const toolStore = useToolState()
|
||||||
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
|
||||||
|
@ -423,7 +424,8 @@ export default {
|
||||||
this.uploadData.levelThirdId = cata[2]
|
this.uploadData.levelThirdId = cata[2]
|
||||||
this.uploadData.textbookId = data.textBook.curBookId
|
this.uploadData.textbookId = data.textBook.curBookId
|
||||||
toolStore.curSubjectNode.data = data
|
toolStore.curSubjectNode.data = data
|
||||||
toolStore.curSubjectNode.querySearch = this.uploadData
|
// 不要同时修改共享数据,这样只会触发一次
|
||||||
|
this.$nextTick(() =>{ toolStore.curSubjectNode.querySearch = this.uploadData })
|
||||||
this.initHomeWork()
|
this.initHomeWork()
|
||||||
await this.asyncAllFile()
|
await this.asyncAllFile()
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,7 +29,7 @@ onMounted(async() => {
|
||||||
const handleMode = (newVal, oldVal) => {
|
const handleMode = (newVal, oldVal) => {
|
||||||
if(toolStore.isPdfWin){
|
if(toolStore.isPdfWin){
|
||||||
if(newVal=='clear'){
|
if(newVal=='clear'){
|
||||||
emit('update:modelValue', oldVal)
|
setTimeout(() => emit('update:modelValue', oldVal), 10)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ const handleMode = (newVal, oldVal) => {
|
||||||
case 'clear': // 清空画布
|
case 'clear': // 清空画布
|
||||||
if(oldVal){
|
if(oldVal){
|
||||||
FabricVue.history?.clean()
|
FabricVue.history?.clean()
|
||||||
emit('update:modelValue', oldVal)
|
setTimeout(() => emit('update:modelValue', oldVal), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<div class="warp" ref="btnRef" :style="isFold?'min-height:auto;':''">
|
<div class="warp" ref="btnRef" :style="isFold?'min-height:auto;':''">
|
||||||
<slot name="start"></slot>
|
<slot name="start"></slot>
|
||||||
<!-- 工具按钮 -->
|
<!-- 工具按钮 -->
|
||||||
|
<transition name="el-zoom-in-bottom">
|
||||||
<el-space direction="vertical" v-show="!isFold">
|
<el-space direction="vertical" v-show="!isFold">
|
||||||
<template v-for="(item,index) in list">
|
<template v-for="(item,index) in list">
|
||||||
<slot :name="item.prop" :item="item" :index="index">
|
<slot :name="item.prop" :item="item" :index="index">
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
</template>
|
</template>
|
||||||
<slot name="append"></slot>
|
<slot name="append"></slot>
|
||||||
</el-space>
|
</el-space>
|
||||||
|
</transition>
|
||||||
<slot name="end">
|
<slot name="end">
|
||||||
<span class="fold" @click="isFold=!isFold" :style="isFold?'margin: 5px;':''">
|
<span class="fold" @click="isFold=!isFold" :style="isFold?'margin: 5px;':''">
|
||||||
{{isFold?'<<<':'>>>'}}
|
{{isFold?'<<<':'>>>'}}
|
||||||
|
|
|
@ -36,6 +36,7 @@ class Drag {
|
||||||
const {cx, cy} = this.getMousePos(e)
|
const {cx, cy} = this.getMousePos(e)
|
||||||
this.x = cx
|
this.x = cx
|
||||||
this.y = cy
|
this.y = cy
|
||||||
|
this.getCurPos() // 被拖拽元素初始坐标
|
||||||
// 手动-触发事件 v-drag-start
|
// 手动-触发事件 v-drag-start
|
||||||
this.el.dispatchEvent(new CustomEvent('v-drag-start', {detail:{drag: this}}))
|
this.el.dispatchEvent(new CustomEvent('v-drag-start', {detail:{drag: this}}))
|
||||||
}
|
}
|
||||||
|
@ -85,12 +86,20 @@ class Drag {
|
||||||
}
|
}
|
||||||
// 获取移动后坐标
|
// 获取移动后坐标
|
||||||
getPos(x, y) {
|
getPos(x, y) {
|
||||||
const w = this.max.w - this.toRound(this.el.clientWidth)
|
// 边界控制:图标元素
|
||||||
const h = this.max.h - this.toRound(this.el.clientHeight)
|
// const w = this.max.w - this.toRound(this.el.clientWidth)
|
||||||
|
// const h = this.max.h - this.toRound(this.el.clientHeight)
|
||||||
|
// 边界控制:整个工具
|
||||||
|
const w = this.max.w - this.toRound(this.handle.clientWidth)
|
||||||
|
const h = this.max.h - this.toRound(this.handle.clientHeight)
|
||||||
x = x < 0 ? 0 : x > w ? w : x
|
x = x < 0 ? 0 : x > w ? w : x
|
||||||
y = y < 0 ? 0 : y > h ? h : y
|
y = y < 0 ? 0 : y > h ? h : y
|
||||||
return { x, y }
|
return { x, y }
|
||||||
}
|
}
|
||||||
|
getCurPos(dom) {
|
||||||
|
const pos = this[dom||'handle']?.getBoundingClientRect()
|
||||||
|
this.data = {left:this.toRound(pos.left), top:this.toRound(pos.top)}
|
||||||
|
}
|
||||||
// 小数转整数
|
// 小数转整数
|
||||||
toRound = v => Math.round(v)
|
toRound = v => Math.round(v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
<el-image :src="logo" draggable="false" />
|
<el-image :src="logo" draggable="false" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tool-btns" v-show="!isFold">
|
<transition name="a-fade">
|
||||||
|
<div class="tool-btns" v-if="!isFold">
|
||||||
<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
|
||||||
@change="tabChange">
|
@change="tabChange">
|
||||||
<template #default="{item}">
|
<template #default="{item}">
|
||||||
|
@ -31,6 +32,7 @@
|
||||||
</template>
|
</template>
|
||||||
</el-segmented>
|
</el-segmented>
|
||||||
</div>
|
</div>
|
||||||
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -41,7 +43,7 @@ import { onMounted, ref, reactive, watchEffect } from 'vue'
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { ElMessageBox, ElMessage, ElLoading } from 'element-plus'
|
import { ElMessageBox, ElMessage, ElLoading } from 'element-plus'
|
||||||
import * as classManageApi from '@/api/classManage'
|
import * as classManageApi from '@/api/classManage'
|
||||||
import logo from '@root/resources/icon.png' // logo
|
import logo from '@root/resources/logo.png' // logo
|
||||||
import boardVue from './components/board.vue' // 画板-子组件
|
import boardVue from './components/board.vue' // 画板-子组件
|
||||||
import sideVue from './components/side.vue' // 画板-子组件
|
import sideVue from './components/side.vue' // 画板-子组件
|
||||||
import upvoteVue from './components/upvote.vue' // 点赞-子组件
|
import upvoteVue from './components/upvote.vue' // 点赞-子组件
|
||||||
|
@ -49,8 +51,9 @@ import imChat from './components/imChat.vue' // im-chat-子组件
|
||||||
import vDrag from './directive/drag' // 自定义指令-拖拽
|
import vDrag from './directive/drag' // 自定义指令-拖拽
|
||||||
import vIgnore from './directive/ignore' // 自定义指令-穿透
|
import vIgnore from './directive/ignore' // 自定义指令-穿透
|
||||||
import { useToolState } from '@/store/modules/tool' // 数据状态-缓存
|
import { useToolState } from '@/store/modules/tool' // 数据状态-缓存
|
||||||
import { ipcMsgSend, ipcHandle, ipcMain, ipcMsgInvoke } from '@/utils/tool' // 相关工具
|
import { ipcMsgSend, ipcMain, sessionStore } from '@/utils/tool' // 相关工具
|
||||||
import MsgEnum from '@/plugins/imChat/msgEnum' // 消息头-相关定义(nuem)
|
import MsgEnum from '@/plugins/imChat/msgEnum' // 消息头-相关定义(nuem)
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const tabActive = ref('select') // 工具栏当前选中项
|
const tabActive = ref('select') // 工具栏当前选中项
|
||||||
const isFold = ref(false) // 折叠工具栏
|
const isFold = ref(false) // 折叠工具栏
|
||||||
|
@ -80,6 +83,7 @@ const btnList = [ // 工具栏按钮列表
|
||||||
// === 页面加载完毕 ===
|
// === 页面加载完毕 ===
|
||||||
onMounted(async() => {
|
onMounted(async() => {
|
||||||
if (!electron) return // 浏览器端
|
if (!electron) return // 浏览器端
|
||||||
|
// console.log(sessionStore)
|
||||||
getClassInfo() // 获取课堂详情 ex3
|
getClassInfo() // 获取课堂详情 ex3
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resetStatus() // 开启重置状态-监听
|
resetStatus() // 开启重置状态-监听
|
||||||
|
@ -102,13 +106,29 @@ const getClassInfo = async () => {
|
||||||
const tabChange = (val) => {
|
const tabChange = (val) => {
|
||||||
const bool = !toolStore.isPdfWin && !toolStore.showBoardAll
|
const bool = !toolStore.isPdfWin && !toolStore.showBoardAll
|
||||||
if(bool) toolStore.showBoardAll = true
|
if(bool) toolStore.showBoardAll = true
|
||||||
// ipcMsgSend('tool-sphere:close')
|
|
||||||
toolStore.model = val // 存储当前tab
|
toolStore.model = val // 存储当前tab
|
||||||
}
|
}
|
||||||
// logo 点击-事件 折叠|展开
|
// logo 点击-事件 折叠|展开
|
||||||
const logoHandle = (e,t) => {
|
const logoHandle = (e,t) => {
|
||||||
if (Date.now() - dragtime.value < 200) {
|
if (Date.now() - dragtime.value < 200) {
|
||||||
isFold.value = !isFold.value
|
isFold.value = !isFold.value
|
||||||
|
setTimeout(() => {
|
||||||
|
// 处理: 工具被拖动到右侧时功能被遮挡
|
||||||
|
const dom = document.querySelector('.tool-bottom-all')
|
||||||
|
const { x } = dom.getBoundingClientRect()
|
||||||
|
const w = window.innerWidth - (470 || 80)
|
||||||
|
// if (x > w) dom.style.left = `${w}px`
|
||||||
|
if (x > w) { // 动画
|
||||||
|
let left = x
|
||||||
|
const animatFn = () => {
|
||||||
|
left-=30
|
||||||
|
if (left < w) left == w
|
||||||
|
dom.style.left = `${left}px`
|
||||||
|
if (left > w) requestAnimationFrame(animatFn)
|
||||||
|
}
|
||||||
|
requestAnimationFrame(animatFn)
|
||||||
|
}
|
||||||
|
}, 20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 底部工具栏:移入移出-是否穿透
|
// 底部工具栏:移入移出-是否穿透
|
||||||
|
@ -262,4 +282,15 @@ watchEffect(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.a-fade-leave-active,.a-fade-enter-active{
|
||||||
|
transition: all .3s;
|
||||||
|
}
|
||||||
|
.a-fade-enter-from,.a-fade-leave-to{
|
||||||
|
width: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.a-fade-enter-to,.a-fade-leave-from{
|
||||||
|
width: 350px;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue