Compare commits

...

22 Commits

Author SHA1 Message Date
朱浩 9f510187c0 二期:教材打开开发 2024-08-07 15:49:37 +08:00
朱浩 3bcb0a2ef3 Merge branch 'main' into zhuhao_dev 2024-08-07 11:13:07 +08:00
朱浩 9018abb673 二期:预约课程修改 2024-08-07 11:12:51 +08:00
朱浩 a55a662ce9 二期:文件大小改为500M 2024-08-07 11:12:38 +08:00
朱浩 528e7876a9 二期:延长本地同步自动计时速率 2024-08-07 11:12:18 +08:00
朱浩 82456a7f96 二期:打包生产配置添加 2024-08-07 11:11:55 +08:00
lyc 74b0cf5fdb Merge pull request 'login 修改' (#103) from lyc-dev into main 2024-08-07 10:32:02 +08:00
lyc df7658a17d login 修改 2024-08-07 10:31:08 +08:00
lyc 8a9fa83c04 Merge pull request '登录修改' (#102) from lyc-dev into main 2024-08-06 15:02:59 +08:00
lyc 9a6f37528c 登录修改 2024-08-06 15:02:40 +08:00
zhengdegang d64b469ac8 Merge pull request 'zdg' (#101) from zdg into main
Reviewed-on: #101
2024-08-05 17:49:43 +08:00
zdg 19901d802f 状态管理-多窗口共享 2024-08-05 17:46:48 +08:00
zdg 22a92ee84b Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk into zdg 2024-08-05 17:11:19 +08:00
zdg 8d558c47f5 多窗口状态共享 2024-08-05 17:10:57 +08:00
lyc 9ab5f65409 Merge pull request 'lyc-dev' (#100) from lyc-dev into main 2024-08-05 17:05:16 +08:00
lyc 95e9fc528a 教材默认图标 2024-08-05 17:03:13 +08:00
lyc e38235fd6b Merge pull request '作业修改' (#99) from lyc-dev into main 2024-08-05 16:25:19 +08:00
lyc 26c46e33c7 Merge branch 'main' into lyc-dev 2024-08-05 16:24:58 +08:00
lyc ce274237dc 作业修改 2024-08-05 16:24:46 +08:00
lyc d46d312b37 Merge pull request 'login' (#98) from lyc-dev into main 2024-08-05 09:49:25 +08:00
lyc fb84977321 login 2024-08-05 09:48:48 +08:00
朱浩 2ef129d5c1 Merge pull request '二期:软件名称修改' (#97) from zhuhao_dev into main
Reviewed-on: #97
2024-08-02 17:13:44 +08:00
22 changed files with 568 additions and 147 deletions

View File

@ -5,15 +5,15 @@ VITE_APP_TITLE = AIx数字平台
VITE_APP_ENV = 'production' VITE_APP_ENV = 'production'
# AIx融合数字管理系统/生产环境 # AIx融合数字管理系统/生产环境
VITE_APP_BASE_API = 'https://file.ysaix.com:7868/prod-api' VITE_APP_BASE_API = 'https://prev.ysaix.com:7868/prod-api'
VITE_APP_DOMAIN = 'file.ysaix.com' VITE_APP_DOMAIN = 'prev.ysaix.com'
VITE_APP_UPLOAD_API = 'https://file.ysaix.com:7868/prod-api' VITE_APP_UPLOAD_API = 'https://prev.ysaix.com:7868/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli # 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip VITE_BUILD_COMPRESS = gzip
VITE_APP_RES_FILE_PATH = 'https://file.ysaix.com:7868/src/assets/textbook/booktxt/' VITE_APP_RES_FILE_PATH = 'https://prev.ysaix.com:7868/src/assets/textbook/booktxt/'
VITE_APP_BUILD_BASE_PATH = 'https://file.ysaix.com:7868/' VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'

19
.env.test Normal file
View File

@ -0,0 +1,19 @@
# 页面标题
VITE_APP_TITLE = AIx数字平台
# 生产环境配置
VITE_APP_ENV = 'production'
# AIx融合数字管理系统/生产环境
VITE_APP_BASE_API = 'https://file.ysaix.com:7868/prod-api'
VITE_APP_DOMAIN = 'file.ysaix.com'
VITE_APP_UPLOAD_API = 'https://file.ysaix.com:7868/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip
VITE_APP_RES_FILE_PATH = 'https://file.ysaix.com:7868/src/assets/textbook/booktxt/'
VITE_APP_BUILD_BASE_PATH = 'https://file.ysaix.com:7868/'

47
electron-builder-prod.yml Normal file
View File

@ -0,0 +1,47 @@
appId: com.electron.app
productName: AIx
directories:
buildResources: build
files:
- '!**/.vscode/*'
- '!src/*'
- '!electron.vite.config.{js,ts,mjs,cjs}'
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
asarUnpack:
- resources/**
win:
executableName: AIx
icon: resources/logo2.ico
nsis:
oneClick: false
allowToChangeInstallationDirectory: true
artifactName: ${name}-${version}-setup.${ext}
shortcutName: ${productName}
uninstallDisplayName: ${productName}
createDesktopShortcut: always
mac:
entitlementsInherit: build/entitlements.mac.plist
extendInfo:
- NSCameraUsageDescription: Application requests access to the device's camera.
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
notarize: false
dmg:
artifactName: ${name}-${version}.${ext}
linux:
target:
- AppImage
- snap
- deb
maintainer: electronjs.org
category: Utility
appImage:
artifactName: ${name}-${version}.${ext}
npmRebuild: false
publish:
provider: generic
url: https://prev.ysaix.com:7868/src/assets/smarttalk/
electronDownload:
mirror: https://npmmirror.com/mirrors/electron/

View File

@ -1,6 +1,6 @@
{ {
"name": "aix-win", "name": "aix-win",
"version": "1.0.2", "version": "1.0.4",
"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",
@ -14,7 +14,8 @@
"postinstall": "electron-builder install-app-deps", "postinstall": "electron-builder install-app-deps",
"build:unpack": "npm run build && electron-builder --dir", "build:unpack": "npm run build && electron-builder --dir",
"build:dev": "npm run build && electron-builder --win --config ./electron-builder-test.yml", "build:dev": "npm run build && electron-builder --win --config ./electron-builder-test.yml",
"build:test": "npm run build && electron-builder --win --config ./electron-builder.yml", "build:test": "electron-vite build --mode test && electron-builder --win --config ./electron-builder.yml",
"build:prod": "electron-vite build --mode production && electron-builder --win --config ./electron-builder-prod.yml",
"build:mac": "npm run build && electron-builder --mac", "build:mac": "npm run build && electron-builder --mac",
"build:linux": "npm run build && electron-builder --linux" "build:linux": "npm run build && electron-builder --linux"
}, },

View File

@ -77,10 +77,10 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
console.error('Error uploading file:', err) console.error('Error uploading file:', err)
} }
}) })
}, 5000) }, 20000)
} }
}) })
}, 1000) }, 10000)
}) })
function getFileMD5(path) { function getFileMD5(path) {

View File

@ -103,11 +103,12 @@ function createMainWindow() {
remote.enable(mainWindow.webContents) remote.enable(mainWindow.webContents)
} }
// 作业窗口相关-开发中 // 打开外部链接窗口
let linkWindow let linkWin = {}
async function createLinkWin(data) { async function createLinkWin(data) {
if (linkWindow) return if (linkWin[data.key]) return
linkWindow = new BrowserWindow({
linkWin[data.key] = new BrowserWindow({
show: false, show: false,
frame: true, frame: true,
maximizable: true, maximizable: true,
@ -120,9 +121,10 @@ async function createLinkWin(data) {
contextIsolation: true contextIsolation: true
} }
}) })
linkWindow.type = 'link' // 唯一标识 linkWin[data.key].type = 'link' // 唯一标识
let cookieDetails = { ...data.cookieData } let cookieDetails = { ...data.cookieData }
await linkWindow.webContents.session.cookies await linkWin[data.key].webContents.session.cookies
.set(cookieDetails) .set(cookieDetails)
.then(() => { .then(() => {
console.log('Cookie is successful') console.log('Cookie is successful')
@ -131,14 +133,15 @@ async function createLinkWin(data) {
console.error('Cookie is error', error) console.error('Cookie is error', error)
}) })
data.fullPath = data.fullPath.replaceAll('//', '/') data.fullPath = data.fullPath.replaceAll('//', '/')
linkWindow.loadURL(data.fullPath) linkWin[data.key].loadURL(data.fullPath)
linkWindow.once('ready-to-show', () => { linkWin[data.key].once('ready-to-show', () => {
linkWindow.show() linkWin[data.key].show()
linkWindow.maximize() linkWin[data.key].maximize()
}) })
linkWindow.on('closed', () => { linkWin[data.key].on('closed', () => {
linkWindow = null linkWin[data.key] = null
delete linkWin[data.key]
}) })
} }
@ -202,14 +205,8 @@ app.on('ready', () => {
ipcMain.on('openWindow', (e, data) => { ipcMain.on('openWindow', (e, data) => {
createLinkWin(data) createLinkWin(data)
}) })
// 新窗口创建-监听 // zdg: 消息监听
ipcMain.on('new-window', (e, data) => { handleAll()
const { id, type } = data
const win = BrowserWindow.fromId(id)
win.type = type // 绑定独立标识
remote.enable(win.webContents) // 开启远程服务
})
// 打开-登录窗口 // 打开-登录窗口
createLoginWindow() createLoginWindow()
@ -226,3 +223,24 @@ app.on('window-all-closed', () => {
app.quit() app.quit()
} }
}) })
// 监听全局事件
function handleAll() {
// 新窗口创建-监听
ipcMain.on('new-window', (e, data) => {
const { id, type } = data
const win = BrowserWindow.fromId(id)
win.type = type // 绑定独立标识
remote.enable(win.webContents) // 开启远程服务
})
// 用于监听-状态管理变化-同步所有窗口
ipcMain.handle('pinia-state-change', (e, storeName, jsonStr) => {
for(const curWin of BrowserWindow.getAllWindows()){
const id = curWin.webContents.id
const bool = id !== e.sender.id && !curWin.isDestroyed()
if (bool) { // 除了消息发送窗口和销毁的窗口 其他都发送
curWin.webContents.send('pinia-state-set', storeName, jsonStr)
}
}
})
}

View File

@ -18,6 +18,15 @@ export function listEntpcourse(query) {
}) })
} }
// 新增entpcourse
export function addEntpcourse(data) {
return request({
url: '/education/entpcourse',
method: 'post',
data: data
})
}
// 布置作业 // 布置作业
export function saveByClassWorkArray(data) { export function saveByClassWorkArray(data) {
return request({ return request({

View File

@ -5,9 +5,9 @@
<span>{{ curBookName }}</span> <span>{{ curBookName }}</span>
<i class="iconfont icon-xiangyou"></i> <i class="iconfont icon-xiangyou"></i>
</div> </div>
<div class="book-list"> <div class="book-list" v-loading="treeLoading">
<el-tree ref="refTree" :data="treeData" :props="defaultProps" node-key="id" <el-tree ref="refTree" :data="treeData" :props="defaultProps" node-key="id"
:default-expanded-keys="defaultExpandedKeys" :current-node-key="currentNode" highlight-current :default-expanded-keys="defaultExpandedKeys" :current-node-key="currentNodeId" highlight-current
@node-click="handleNodeClick"> @node-click="handleNodeClick">
<template #default="{ node }"> <template #default="{ node }">
<span :title="node.label" class="tree-label">{{ node.label }}</span> <span :title="node.label" class="tree-label">{{ node.label }}</span>
@ -30,7 +30,10 @@
<el-scrollbar height="450px"> <el-scrollbar height="450px">
<div class="textbook-item flex" v-for="item in subjectList" :class="curBookId == item.id ? 'active-item' : ''" <div class="textbook-item flex" v-for="item in subjectList" :class="curBookId == item.id ? 'active-item' : ''"
:key="item.id" @click="changeBook(item)"> :key="item.id" @click="changeBook(item)">
<img :src="BaseUrl + item.avartar" class="textbook-img" alt=""> <img v-if="item.avartar" :src="BaseUrl + item.avartar" class="textbook-img" alt="">
<div v-else class="textbook-img">
<i class="iconfont icon-jiaocaixuanze" style="font-size: 40px;"></i>
</div>
<span class="book-name">{{ item.itemtitle }}</span> <span class="book-name">{{ item.itemtitle }}</span>
</div> </div>
</el-scrollbar> </el-scrollbar>
@ -39,7 +42,7 @@
</template> </template>
<script setup> <script setup>
import { onMounted, ref, nextTick, toRaw } from 'vue'; import { onMounted, ref, nextTick, toRaw, reactive } from 'vue';
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { listEvaluation } from '@/api/subject' import { listEvaluation } from '@/api/subject'
@ -60,18 +63,26 @@ const defaultProps = {
label: 'label', label: 'label',
class: 'textbook-tree' class: 'textbook-tree'
} }
const treeLoading = ref(false)
//ID //ID
const curBookId = ref(-1) const curBookId = ref(-1)
// //
const curBookName = ref('') const curBookName = ref('')
// //
const curBookImg = ref('') const curBookImg = ref('')
//
const curBookPath = ref('')
// //
const volumeOne = ref([]) const volumeOne = ref([])
// //
const volumeTwo = ref([]) const volumeTwo = ref([])
//
const currentNode = reactive({
data:{}
})
// ID // ID
const currentNode = ref(0) const currentNodeId = ref(0)
// //
const currentNodeName = ref('') const currentNodeName = ref('')
// //
@ -82,6 +93,7 @@ const refTree = ref(null)
// //
const getSubjectContent = async () => { const getSubjectContent = async () => {
treeLoading.value = true
const params = { const params = {
edusubject, edusubject,
edustage, edustage,
@ -93,12 +105,17 @@ const getSubjectContent = async () => {
if (localStorage.getItem('evaluationList')) { if (localStorage.getItem('evaluationList')) {
evaluationList.value = JSON.parse(localStorage.getItem('evaluationList')) evaluationList.value = JSON.parse(localStorage.getItem('evaluationList'))
data = evaluationList.value data = evaluationList.value
treeLoading.value = false
} }
else { else {
const { rows } = await listEvaluation(params) try {
localStorage.setItem('evaluationList', JSON.stringify(rows)) const { rows } = await listEvaluation(params)
evaluationList.value = rows localStorage.setItem('evaluationList', JSON.stringify(rows))
data = rows evaluationList.value = rows
data = rows
} finally {
treeLoading.value = false
}
} }
// //
@ -107,15 +124,15 @@ const getSubjectContent = async () => {
volumeOne.value = data.filter(item => item.level == 1 && item.semester == '上册') volumeOne.value = data.filter(item => item.level == 1 && item.semester == '上册')
// //
volumeTwo.value = data.filter(item => item.level == 1 && item.semester == '下册') volumeTwo.value = data.filter(item => item.level == 1 && item.semester == '下册')
getTreeData() getTreeData()
} }
// //
const changeBook = ({ id, itemtitle, avartar }) => { const changeBook = ({ id, itemtitle, avartar, fileurl }) => {
curBookId.value = id curBookId.value = id
curBookName.value = itemtitle curBookName.value = itemtitle
curBookImg.value = BaseUrl + avartar curBookImg.value = BaseUrl + avartar
curBookPath.value = fileurl
getTreeData() getTreeData()
setTimeout(() => { setTimeout(() => {
dialogVisible.value = false dialogVisible.value = false
@ -126,10 +143,20 @@ const getTreeData = () => {
// //
let upData = transData(volumeOne.value) let upData = transData(volumeOne.value)
let downData = transData(volumeTwo.value) let downData = transData(volumeTwo.value)
treeData.value = upData.length ? upData : downData if(upData.length && downData.length){
defaultExpandedKeys.value = [treeData.value[0].id] treeData.value = [...upData,...downData]
}
else if(upData.length || downData.length){
treeData.value = upData.length ? upData : downData
}
else{
treeData.value = []
return
}
nextTick(() => { nextTick(() => {
currentNode.value = getLastLevelData(treeData.value)[0].id defaultExpandedKeys.value = [treeData.value[0].id]
currentNode.data = getLastLevelData(treeData.value)[0]
currentNodeId.value = getLastLevelData(treeData.value)[0].id
currentNodeName.value = getLastLevelData(treeData.value)[0].label currentNodeName.value = getLastLevelData(treeData.value)[0].label
emitChangeBook() emitChangeBook()
}) })
@ -138,17 +165,22 @@ const getTreeData = () => {
const emitChangeBook = () => { const emitChangeBook = () => {
let curNode = { let curNode = {
id: currentNode.value, id: currentNodeId.value,
label: currentNodeName.value label: currentNodeName.value,
itemtitle: currentNode.data.itemtitle,
edudegree: currentNode.data.edudegree,
edustage: currentNode.data.edustage,
edusubject: currentNode.data.edusubject,
} }
let parentNode = findParentByChildId(treeData.value, currentNode.value) let parentNode = findParentByChildId(treeData.value, currentNodeId.value)
curNode.parentNode = toRaw(parentNode) curNode.parentNode = toRaw(parentNode)
const data = { const data = {
textBook: { textBook: {
curBookId: curBookId.value, curBookId: curBookId.value,
curBookName: curBookName.value, curBookName: curBookName.value,
curBookImg: curBookImg.value curBookImg: curBookImg.value,
curBookPath: curBookPath.value
}, },
node: curNode node: curNode
} }
@ -201,20 +233,26 @@ const findParentByChildId = (treeData, targetNodeId) => {
const transData = (data) => { const transData = (data) => {
let ary = [] let ary = []
data.forEach(item => { data.forEach(item => {
let obj = {} let obj = {}
if (item.rootid == curBookId.value) { if (item.rootid == curBookId.value) {
obj.label = item.itemtitle obj.label = item.itemtitle
obj.id = item.id obj.id = item.id
obj.itemtitle = item.itemtitle
obj.edudegree = item.edudegree
obj.edustage = item.edustage
obj.edusubject = item.edusubject
let ary2 = [] let ary2 = []
evaluationList.value.forEach(el => { evaluationList.value.forEach(el => {
let obj2 = {} let obj2 = {}
if (item.id == el.parentid) { if (item.id == el.parentid) {
obj2 = { obj2 = {
label: el.itemtitle, label: el.itemtitle,
id: el.id id: el.id,
itemtitle : el.itemtitle,
edudegree : el.edudegree,
edustage : el.edustage,
edusubject : el.edusubject,
} }
ary2.push(obj2) ary2.push(obj2)
} }
@ -236,11 +274,13 @@ const getSubject = async () => {
subjectList.value = rows.filter(item => item.edustage == edustage && item.edusubject == edusubject && isHaveUnit(item.id)) subjectList.value = rows.filter(item => item.edustage == edustage && item.edusubject == edusubject && isHaveUnit(item.id))
localStorage.setItem('subjectList', JSON.stringify(subjectList.value)) localStorage.setItem('subjectList', JSON.stringify(subjectList.value))
} }
// //
if(!subjectList.value.length) return
curBookName.value = subjectList.value[0].itemtitle curBookName.value = subjectList.value[0].itemtitle
curBookId.value = subjectList.value[0].id curBookId.value = subjectList.value[0].id
curBookImg.value = BaseUrl + subjectList.value[0].avartar curBookImg.value = BaseUrl + subjectList.value[0].avartar
curBookPath.value = subjectList.value[0].fileurl
} }
@ -256,25 +296,27 @@ const handleNodeClick = (data, node) => {
* data : 当前节点数据 * data : 当前节点数据
* node : 当前节点对象 包含当前节点所有数据 parent属性 指向父节点Node对象 * node : 当前节点对象 包含当前节点所有数据 parent属性 指向父节点Node对象
*/ */
const currentNode = data;
const nodeData = data;
const parentNode = node.parent.data; const parentNode = node.parent.data;
if (Array.isArray(parentNode)) { if (Array.isArray(parentNode)) {
currentNode.parentNode = null nodeData.parentNode = null
} }
else { else {
currentNode.parentNode = parentNode nodeData.parentNode = parentNode
} }
let curData = { let curData = {
textBook: { textBook: {
curBookId: curBookId.value, curBookId: curBookId.value,
curBookName: curBookName.value, curBookName: curBookName.value,
curBookImg: curBookImg.value curBookImg: curBookImg.value,
curBookPath: curBookPath.value
}, },
node: toRaw(currentNode) node: toRaw(nodeData)
} }
currentNode.data = curData
emit('nodeClick', curData) emit('nodeClick', curData)
} }
@ -365,6 +407,9 @@ onMounted(() => {
.textbook-img { .textbook-img {
width: 55px; width: 55px;
height: 70px; height: 70px;
display: flex;
align-items: center;
justify-content: center;
} }
} }
@ -389,4 +434,4 @@ onMounted(() => {
background-color: #eaf3ff !important; background-color: #eaf3ff !important;
color: #409EFF color: #409EFF
} }
</style> </style>

View File

@ -137,7 +137,6 @@ const getSubjectContent = async () => {
volumeOne.value = data.filter(item => item.level == 1 && item.semester == '上册') volumeOne.value = data.filter(item => item.level == 1 && item.semester == '上册')
// //
volumeTwo.value = data.filter(item => item.level == 1 && item.semester == '下册') volumeTwo.value = data.filter(item => item.level == 1 && item.semester == '下册')
getTreeData() getTreeData()
} }
@ -154,6 +153,7 @@ const getSubject = async () => {
} }
// //
if(!subjectList.value.length) return
curBookName.value = subjectList.value[0].itemtitle curBookName.value = subjectList.value[0].itemtitle
curBookId.value = subjectList.value[0].id curBookId.value = subjectList.value[0].id
} }
@ -168,7 +168,17 @@ const getTreeData = () => {
// //
let upData = transData(volumeOne.value) let upData = transData(volumeOne.value)
let downData = transData(volumeTwo.value) let downData = transData(volumeTwo.value)
treeData.value = upData.length ? upData : downData
if(upData.length && downData.length){
treeData.value = [...upData,...downData]
}
else if(upData.length || downData.length){
treeData.value = upData.length ? upData : downData
}
else{
treeData.value = []
return
}
nextTick(() => { nextTick(() => {
defaultExpandedKeys.value = [treeData.value[0].id] defaultExpandedKeys.value = [treeData.value[0].id]
currentNodeId.value = getLastLevelData(treeData.value)[0].id currentNodeId.value = getLastLevelData(treeData.value)[0].id

View File

@ -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>

View File

@ -96,9 +96,9 @@ const hanleFileChange = (file) => {
return false return false
} }
// //
// B < KB < MB < GB // B < KB < MB < GB
// file.raw.size B // file.raw.size B
const fileSize = file.raw.size / 1024 / 1024 > 100 const fileSize = file.raw.size / 1024 / 1024 > 500
if (fileSize) { if (fileSize) {
ElMessage.error('文件大小错误! 请上传小于100M的文件!') ElMessage.error('文件大小错误! 请上传小于100M的文件!')
return false return false
@ -126,7 +126,7 @@ const checkFile = (item, file) => {
else{ else{
return false return false
} }
} }
// //

View File

@ -118,7 +118,7 @@ export default {
file.callback(res) file.callback(res)
}, },
beforeUpload(file) { beforeUpload(file) {
const MAX_SIZE = 100 * 1024 * 1024 // 2MB const MAX_SIZE = 500 * 1024 * 1024 // 2MB
if (file.size > MAX_SIZE) { if (file.size > MAX_SIZE) {
this.$message.error('文件大小不能超过 100MB!') this.$message.error('文件大小不能超过 100MB!')
return false return false

View File

@ -0,0 +1,41 @@
/**
* 共享数据状态-多窗口
*/
const { ipcRenderer } = require('electron') // app使用
export function shareStorePlugin({store}) {
store.$subscribe(() => { // 自动同步
// 在存储变化的时候执行
const storeName = store.$id
// 用于多窗口共享(需要共享的状态名称)
const names = ['tool']
if (names.includes(storeName)) stateSync(store) // 需要同步
})
// 暴露方法-手动同步
store.stateSync = () => stateSync(store)
// 监听主线程消息-同步数据
stateChange(store)
}
// 同步数据-发送给主线程
function stateSync(store) {
const storeName = store.$id
const jsonStr = JSON.stringify(store.$state)
// 通知主线程更新
ipcRenderer.invoke('pinia-state-change', storeName, jsonStr)
}
// 同步数据-接收主线程消息
function stateChange(store) {
const storeName = store.$id
ipcRenderer.on('pinia-state-set', (e, sName, jsonStr) => {
if (sName == storeName) { // 更新对应数据
console.log('state-set', jsonStr, sName)
const curJson = JSON.stringify(store.$state) // 当前数据
const isUp = curJson != jsonStr // 不同的时候才写入,不然会导致触发数据变化监听,导致死循环
if (!isUp) return
const stateJson = JSON.parse(jsonStr) // 新数据
// 更新状态
store.$patch(stateJson)
// 您可以通过将其 $state 属性设置为新对象来替换 Store 的整个状态
// store.$state = stateJson
}
})
}

View File

@ -1,7 +1,9 @@
import { createPinia } from 'pinia' import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import { shareStorePlugin } from '@/plugins/shareStore'
const pinia = createPinia() //创建pinia实例 const pinia = createPinia() //创建pinia实例
pinia.use(piniaPluginPersistedstate) //将插件添加到 pinia 实例上 pinia.use(piniaPluginPersistedstate) //将插件添加到 pinia 实例上
pinia.use(shareStorePlugin) // 多窗口数据状态共享
export const store = pinia export const store = pinia

View File

@ -0,0 +1,13 @@
/**
* 工具类-窗口-状态管理
*/
import { defineStore } from 'pinia'
export const useToolState = defineStore('tool', {
state: () => ({
model: 'select', // 悬浮球-当前模式
showBoardAll: false, // 全屏画板-是否显示
}),
actions: {
}
})

View File

@ -17,7 +17,7 @@ const uploaderStore = defineStore('uploader', {
pushFile(payload) { pushFile(payload) {
let _this = this let _this = this
let arr = payload.filter((item) => { let arr = payload.filter((item) => {
const MAX_SIZE = 100 * 1024 * 1024; // 2MB const MAX_SIZE = 500 * 1024 * 1024; // 2MB
if (item.size > MAX_SIZE) { if (item.size > MAX_SIZE) {
ElMessage.error('文件大小不能超过 100MB!'); ElMessage.error('文件大小不能超过 100MB!');
return false; return false;

View File

@ -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,13 +48,14 @@ 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: '请输入您的账号' }],
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }] password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }]
}) })
let curWinUrl; let curWinUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH;
// //
const submitForm = async (formEl) => { const submitForm = async (formEl) => {
@ -131,9 +132,7 @@ const setCookie = (name, value) => {
onMounted(() => { onMounted(() => {
// URL localStorage.clear()
curWinUrl = BrowserWindow.getFocusedWindow().webContents.getURL()
getCookie() getCookie()
}) })
</script> </script>

View File

@ -0,0 +1,129 @@
<template>
<el-dialog
v-model="centerDialogVisible"
class="reserv-dialog"
title="预约课程"
destroy-on-close
width="600"
style="text-align: left"
>
<el-form :model="form" label-width="auto" style="max-width: 600px">
<el-form-item label="课程名称">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="课程类型" prop="location">
<el-segmented v-model="form.type" :block="false" :options="locationOptions" />
</el-form-item>
<el-form-item label="&nbsp;" prop="location">
<div>{{ locationMessage }}</div>
</el-form-item>
<el-form-item label="上课时间">
<el-col :span="6">
<el-date-picker
v-model="form.day"
type="date"
:editable="false"
class="reserv-date-pick"
placeholder="请选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</el-col>
<el-col :span="2" class="text-center">
<span class="text-gray-500">-</span>
</el-col>
<el-col :span="11">
<el-time-picker
v-model="form.time"
is-range
:editable="false"
format="HH:mm"
class="reserv-time-pick"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
/>
</el-col>
</el-form-item>
<el-form-item label="授课对象">
<el-radio-group v-model="form.resource">
<el-radio v-for="(item, index) in classList" :key="index" :value="item.id">{{item.caption}}({{item.classstudentcount}})</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="教室">
<el-input v-model="form.classRoom" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="centerDialogVisible = false">取消</el-button>
<el-button type="primary" @click="centerDialogVisible = false"> 提交 </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, defineExpose, onMounted, reactive, computed } from 'vue'
import { listClassmain } from '@/api/classManage'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore().user
const centerDialogVisible = ref(false)
const form = reactive({
name: '',
type: '常规课',
delivery: false,
day:'',
time:'',
resource: '',
classRoom: ''
})
const locationOptions = [
{
label: '常规课',
value: '常规课',
disabled: false,
message: '现场公屏授课,学生无需长时间打开平板上。'
},
{
label: '公开课',
value: '公开课',
disabled: true,
message: '现场公屏授课,学生需打开平开与老师进行互动,如点赞、互动作业。'
},
{
label: '直播课',
value: '直播课',
disabled: true,
message: '远程直播授课,学生需打开平开观看实时直播教学,并与老师进行互动。'
}
]
const locationMessage = computed(() => {
return locationOptions.find((item) => item.value === form.type).message
})
const openDialog = () => {
centerDialogVisible.value = true
}
const closeDialog = () => {
centerDialogVisible.value = false
}
const classList = ref([])
onMounted(() => {
listClassmain({ classuserid: userStore.userId, pageSize: 100, status: 'open' }).then(
(response) => {
classList.value = [...response.rows]
}
)
})
defineExpose({
openDialog,
closeDialog
})
</script>
<style scoped lang="scss">
:deep(.reserv-date-pick) {
width: 140px;
}
:deep(.reserv-time-pick) {
width: 240px;
}
</style>

View File

@ -3,18 +3,17 @@
<ChooseTextbook @change-book="nodeClick" @node-click="nodeClick" /> <ChooseTextbook @change-book="nodeClick" @node-click="nodeClick" />
<div class="page-right"> <div class="page-right">
<div class="header-top flex"> <div class="header-top flex">
<div class="textbook-img"> <div class="textbook-img" @click="navtoPdf">
<el-image style="width: 80px; height: 110px" :src="curBookImg" /> <el-image style="width: 80px; height: 110px" :src="curBookImg" />
</div> </div>
<div class="top-item"> <div class="top-item">
<el-button class="btn" @click="handleOutLink('standard')">课标研读</el-button> <el-button class="btn" @click="handleOutLink('standard')">课标研读</el-button>
<el-button class="btn" @click="navtoPdf">电子课本</el-button> <el-button class="btn" @click="openReserv">预约课程</el-button>
<el-button class="btn" @click="handleOutLink('gk')">高考研读</el-button> <el-button class="btn" @click="handleOutLink('gk')">高考研读</el-button>
<el-button class="btn" @click="handleOutLink('aiModel')">教学大模型</el-button> <el-button class="btn" @click="handleOutLink('aiModel')">教学大模型</el-button>
</div> </div>
<el-button type="primary" class="to-class-btn" @click="openLesson"> <el-button type="primary" class="to-class-btn" @click="openLesson">
<i class="iconfont icon-lingdang"></i>上课</el-button <i class="iconfont icon-lingdang"></i>上课</el-button>
>
<div class="top-zoom-style"></div> <div class="top-zoom-style"></div>
</div> </div>
<div class="prepare-body-header"> <div class="prepare-body-header">
@ -23,13 +22,7 @@
<el-popover placement="top-start" :width="250" trigger="hover"> <el-popover placement="top-start" :width="250" trigger="hover">
<template #default> <template #default>
<div> <div>
<el-button <el-button v-if="lastAsyncAllTime" type="success" size="small" :icon="Check" circle />
v-if="lastAsyncAllTime"
type="success"
size="small"
:icon="Check"
circle
/>
{{ lastAsyncAllTime ? toTimeText(lastAsyncAllTime) + '同步成功' : '' }} {{ lastAsyncAllTime ? toTimeText(lastAsyncAllTime) + '同步成功' : '' }}
</div> </div>
</template> </template>
@ -47,49 +40,33 @@
<el-button @click="handleOutLink('feedback')">作业反馈</el-button> <el-button @click="handleOutLink('feedback')">作业反馈</el-button>
<el-button @click="handleOutLink('homeWork')">布置作业</el-button> <el-button @click="handleOutLink('homeWork')">布置作业</el-button>
<el-button @click="isDialogOpen = true">上传资料</el-button> <el-button @click="isDialogOpen = true">上传资料</el-button>
<el-button type="primary" style="margin-left: 10px" @click="createFile" <el-button type="primary" style="margin-left: 10px" @click="createFile">新建课件</el-button>
>新建课件</el-button
>
</div> </div>
</div> </div>
<el-checkbox-group <el-checkbox-group v-model="checkFileList" class="prepare-body-main"
v-model="checkFileList" :style="{ 'margin-bottom': checkFileList.length > 0 ? '40px' : '0' }">
class="prepare-body-main" <file-list-item v-for="(item, index) in currentFileList" :key="index" :item="item" :index="index"
:style="{ 'margin-bottom': checkFileList.length > 0 ? '40px' : '0' }" @on-move="onMoveSingleFile" @on-delete="deleteTalk" @on-set="openSet" @on-delhomework="delhomework">
> <el-checkbox label="" :value="item" v-if="!item.uniquekey" />
<file-list-item
v-for="(item, index) in currentFileList"
:key="index"
:item="item"
:index="index"
@on-move="onMoveSingleFile"
@on-delete="deleteTalk"
@on-set="openSet"
@on-delhomework="delhomework"
>
<el-checkbox label="" :value="item" v-if="!item.uniquekey"/>
</file-list-item> </file-list-item>
</el-checkbox-group> </el-checkbox-group>
<file-oper-batch <file-oper-batch v-show="checkFileList.length > 0"
v-show="checkFileList.length > 0"
:indeterminate="checkFileList.length > 0 && checkFileList.length < currentFileList.length" :indeterminate="checkFileList.length > 0 && checkFileList.length < currentFileList.length"
:choose="checkFileList" :choose="checkFileList" :check-all="isCheckAll" @click-delete="clickDelete" @click-move="clickMove"
:check-all="isCheckAll" @cancel="checkFileList = []" @click-choose="clickChoose"></file-oper-batch>
@click-delete="clickDelete"
@click-move="clickMove"
@cancel="checkFileList = []"
@click-choose="clickChoose"
></file-oper-batch>
</div> </div>
<MoveFile v-model="isMoveDialogOpen" @on-submit="chooseMoveCata" /> <MoveFile v-model="isMoveDialogOpen" @on-submit="chooseMoveCata" />
<uploadDialog v-model="isDialogOpen" @submit-file="submitFile" /> <uploadDialog v-model="isDialogOpen" @submit-file="submitFile" />
<SetHomework v-model="setDialog" :entpcourseid="entpcourseid" :row="row" @on-close="closeHomework" /> <SetHomework v-model="setDialog" :entpcourseid="entpcourseid" :row="row" @on-close="closeHomework" />
</div> </div>
<reserv ref="reservDialog"></reserv>
</template> </template>
<script setup> <script setup>
import { Check } from '@element-plus/icons-vue' import { Check } from '@element-plus/icons-vue'
import Reserv from '@/views/prepare/container/reserv.vue'
</script> </script>
<script> <script>
const Remote = require('@electron/remote')
import ChooseTextbook from '@/components/choose-textbook/index.vue' import ChooseTextbook from '@/components/choose-textbook/index.vue'
import uploadDialog from '@/components/upload-dialog/index.vue' import uploadDialog from '@/components/upload-dialog/index.vue'
import { Refresh } from '@element-plus/icons-vue' import { Refresh } from '@element-plus/icons-vue'
@ -107,8 +84,8 @@ import SetHomework from './container/set-homework.vue'
import outLink from '@/utils/linkConfig' import outLink from '@/utils/linkConfig'
import { createWindow } from '@/utils/tool' import { createWindow } from '@/utils/tool'
import { uniqBy, cloneDeep } from 'lodash' import { uniqBy, cloneDeep } from 'lodash'
import { delClasswork } from '@/api/teaching/classwork' import { delClasswork, addEntpcourse } from '@/api/teaching/classwork'
const fs = require('fs');
const { ipcRenderer } = window.electron || {} const { ipcRenderer } = window.electron || {}
export default { export default {
@ -134,6 +111,7 @@ export default {
fileList: [], fileList: [],
currentNode: {}, currentNode: {},
currentFileList: [], currentFileList: [],
curBookPath: '',
lastAsyncAllTime: '', lastAsyncAllTime: '',
uploadData: { uploadData: {
textbookId: null, textbookId: null,
@ -170,18 +148,52 @@ export default {
created() { created() {
this.userStore = useUserStore().user this.userStore = useUserStore().user
ipcRenderer.removeAllListeners('copy-file-default-reply') ipcRenderer.removeAllListeners('copy-file-default-reply')
ipcRenderer.on('copy-file-default-reply', (e, param) => { ipcRenderer.on('copy-file-default-reply', (e, param) => {
this.callback(param) this.callback(param)
}) })
this.lastAsyncAllTime = localStorage.getItem('lastAsyncAllTime') this.lastAsyncAllTime = localStorage.getItem('lastAsyncAllTime')
}, },
mounted() {}, mounted() { },
activated() { activated() {
if (this.uploadData.textbookId !== null) { if (this.uploadData.textbookId !== null) {
this.asyncAllFile() this.asyncAllFile()
this.initHomeWork()
} }
}, },
methods: { methods: {
getBookPathFromServer() {
let fileName = this.curBookPath
if (!fileName) return
fileName = fileName.replace('.txt', '.pdf')
return new Promise((resolve, reject)=>{
const userDataPath = Remote.app.getPath('userData')
const appRootFilePath = userDataPath + '\\selfFile\\'
let filePath = appRootFilePath + fileName
fs.access(filePath, fs.constants.F_OK, (err) => {
let filePath = import.meta.env.VITE_APP_RES_FILE_PATH + fileName
if (err) {
//线
ipcRenderer.send('download-file-default', {
url: filePath,
fileName: fileName
})
ipcRenderer.once('download-file-default' + fileName, (e, isSuccess) => {
if (isSuccess === true) {
resolve(appRootFilePath + fileName)
}else {
ElMessage({
type: 'info',
message: `下载教材失败!`
})
}
})
}else {
resolve(appRootFilePath + fileName)
}
})
})
},
createFile() { createFile() {
creatPPT(this.currentNode.label + '.pptx', this.uploadData).then((res) => { creatPPT(this.currentNode.label + '.pptx', this.uploadData).then((res) => {
this.currentFileList.unshift(res.resData) this.currentFileList.unshift(res.resData)
@ -301,8 +313,10 @@ export default {
}) })
}, },
async nodeClick(data) { async nodeClick(data) {
console.log(data)
if (this.currentNode.id === data.node.id) return if (this.currentNode.id === data.node.id) return
this.curBookImg = data.textBook.curBookImg this.curBookImg = data.textBook.curBookImg
this.curBookPath = data.textBook.curBookPath
this.checkFileList = [] this.checkFileList = []
let cata = parseCataByNode(data.node) let cata = parseCataByNode(data.node)
this.currentNode = data.node this.currentNode = data.node
@ -310,17 +324,54 @@ export default {
this.uploadData.levelSecondId = cata[1] this.uploadData.levelSecondId = cata[1]
this.uploadData.levelThirdId = cata[2] this.uploadData.levelThirdId = cata[2]
this.uploadData.textbookId = data.textBook.curBookId this.uploadData.textbookId = data.textBook.curBookId
this.initHomeWork()
await this.asyncAllFile() await this.asyncAllFile()
},
async initHomeWork() {
if (this.timerId) {
clearInterval(this.timerId)
}
if (this.uploadData.levelSecondId) { if (this.uploadData.levelSecondId) {
// ID // ID
const { rows } = await this.getChapterId() let { rows } = await this.getChapterId()
if(!rows.length) return if (rows.length > 0) {
this.entpcourseid = rows[0].id this.entpcourseid = rows[0].id
}
else{
await this.createEntpcourse()
let { rows } = await this.getChapterId()
this.entpcourseid = rows[0].id
}
// //
this.getHomeWorkList() this.getHomeWorkList()
} }
}, },
// entpcourse
createEntpcourse() {
var cform = {};
cform.entpid = this.userStore.deptId;
cform.level = 1;
cform.parentid = 0;
cform.dictid = 0;
cform.evalid = this.currentNode.id;
cform.evalparentid = 0;
cform.edusubject = this.currentNode.edusubject;
cform.edudegree = this.currentNode.edudegree;
cform.edustage = this.currentNode.edustage;
cform.coursetype = '课标学科';
cform.coursetitle = this.currentNode.itemtitle;
cform.coursedesc = '';
cform.status = '';
cform.dflag = 0;
cform.edituserid = this.userStore.userId;
cform.createblankfile = 'yes';
return addEntpcourse(cform)
},
openReserv(){
// this.$refs['reservDialog'].openDialog()
},
// //
handleOutLink(key) { handleOutLink(key) {
if (key == 'homeWork') { if (key == 'homeWork') {
@ -331,6 +382,7 @@ export default {
let configObj = outLink()[key] let configObj = outLink()[key]
// //
ipcRenderer.send('openWindow', { ipcRenderer.send('openWindow', {
key,
fullPath: configObj.fullPath, fullPath: configObj.fullPath,
cookieData: { ...configObj.data } cookieData: { ...configObj.data }
}) })
@ -343,7 +395,7 @@ export default {
pageSize: 500 pageSize: 500
}) })
}, },
// //
createTimer() { createTimer() {
this.timerId = setInterval(() => { this.timerId = setInterval(() => {
this.getHomeWorkList() this.getHomeWorkList()
@ -421,22 +473,25 @@ export default {
this.setDialog = true this.setDialog = true
}, },
// //
delhomework(item){ delhomework(item) {
this.isLoading = true this.isLoading = true
delClasswork(item.id).then( async res =>{ delClasswork(item.id).then(async res => {
ElMessage.success('操作成功') ElMessage.success('操作成功')
this.isLoading = false this.isLoading = false
await this.asyncAllFile() await this.asyncAllFile()
this.getHomeWorkList() this.getHomeWorkList()
}).catch(()=>{ }).catch(() => {
this.isLoading = false this.isLoading = false
}) })
}, },
closeHomework() { closeHomework() {
this.setDialog = false this.setDialog = false
}, },
// PDF- // PDF-
navtoPdf() { async navtoPdf() {
let path = await this.getBookPathFromServer()
console.log(path)
createWindow('open-PDF', { url: '/classBegins/index' }) createWindow('open-PDF', { url: '/classBegins/index' })
}, },
// - // -
@ -516,6 +571,9 @@ export default {
overflow: hidden; overflow: hidden;
margin-right: 20px; margin-right: 20px;
z-index: 1; z-index: 1;
&:hover {
cursor: pointer;
}
} }
.top-item { .top-item {

View File

@ -23,7 +23,6 @@
</div> </div>
<!-- 上传弹窗 --> <!-- 上传弹窗 -->
<uploadDialog v-model="isDialogOpen" @submit-file="submitFile" /> <uploadDialog v-model="isDialogOpen" @submit-file="submitFile" />
<!-- <el-button @click="testClick">测试</el-button> -->
</template> </template>
<script setup> <script setup>
@ -35,22 +34,17 @@ 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 { createWindow } from '@/utils/tool' import { createWindow } from '@/utils/tool'
// import { useToolState } from '@/store/modules/tool'
const sourceStore = useResoureStore() const sourceStore = useResoureStore()
const isDialogOpen = ref(false) const isDialogOpen = ref(false)
const toolStore = useToolState()
const openDialog = () => { const openDialog = () => {
isDialogOpen.value = true isDialogOpen.value = true
} }
onMounted(async () => { // onMounted(async () => {
// const params = { url: '/tool/sphere' } // console.log('toolStore: ', toolStore.windowState)
// const res = await ipcMsgSend('tool-sphere:create', params) // })
// console.log('', res)
})
const testClick = async () => {
const win = await createWindow('tool-sphere', { url: '/tool/sphere' })
console.log('消息返回:', win)
}
// //
const getData = (data) => { const getData = (data) => {
const { textBook, node } = data const { textBook, node } = data

View File

@ -1,6 +1,8 @@
<template> <template>
<canvas ref="canvasRef" /> <div>
<slot></slot> <canvas ref="canvasRef" />
<slot></slot>
</div>
</template> </template>
<script setup> <script setup>
// //

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="warp-all"> <div class="warp-all">
<board-vue v-model="tabActive"></board-vue> <board-vue v-model="tabActive" v-show="isShow"></board-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)">
@ -27,18 +27,20 @@
<script setup> <script setup>
// electron // electron
import { onMounted, ref, reactive } 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 vDrag from './directive/drag' import vDrag from './directive/drag' // -
// const Remote = require('@electron/remote') // remote import { useToolState } from '@/store/modules/tool'
const { ipcRenderer } = require('electron') // app使 const { ipcRenderer } = require('electron') // app使
// const ipcRenderer = { send: () => {} } // 使 // const ipcRenderer = { send: () => {} } // 使
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 toolStore = useToolState()
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' },
@ -48,9 +50,17 @@ const btnList = [ // 工具栏按钮列表
// { 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 // -
// console.log('xxx: ', toolStore.model)
// setTimeout(() => {
// toolStore.windowState.test = ''
// }, 2000);
})
// ==== === // ==== ===
const tabChange = (val) => { // tab-change const tabChange = (val) => { // tab-change
console.log(val) // console.log('xxxx:', val)
toolStore.showBoardAll = true
switch (val) { switch (val) {
case 'brush': // case 'brush': //
break break
@ -68,6 +78,7 @@ const tabChange = (val) => { // 切换tab-change
default: default:
break break
} }
toolStore.model = val // tab
} }
const logoHandle = (e,t) => { // logo - | const logoHandle = (e,t) => { // logo - |
if (Date.now() - dragtime.value < 200) { if (Date.now() - dragtime.value < 200) {
@ -80,6 +91,9 @@ const mouseChange = (bool) => { // 鼠标移入工具栏 是否穿透
if (tabActive.value == 'select') resBool = !!bool if (tabActive.value == 'select') resBool = !!bool
ipcRenderer.send('tool-sphere:set:ignore', resBool) ipcRenderer.send('tool-sphere:set:ignore', resBool)
} }
watchEffect(() => { //
isShow.value = toolStore.showBoardAll // -
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>