Merge branch 'zdg' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk into zdg
# Conflicts: # src/main/index.js # src/renderer/src/assets/iconfont/iconfont.css # src/renderer/src/assets/iconfont/iconfont.ttf # src/renderer/src/assets/iconfont/iconfont.woff # src/renderer/src/assets/iconfont/iconfont.woff2 # src/renderer/src/views/resource/index.vue
This commit is contained in:
commit
e6a854b1a2
|
@ -1,3 +1,3 @@
|
||||||
provider: generic
|
provider: generic
|
||||||
url: https://example.com/auto-updates
|
url: http://localhost:3000/
|
||||||
updaterCacheDirName: electron-app-updater
|
updaterCacheDirName: electron-app-updater
|
||||||
|
|
|
@ -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: http://localhost:3000
|
||||||
|
electronDownload:
|
||||||
|
mirror: https://npmmirror.com/mirrors/electron/
|
|
@ -12,6 +12,7 @@ asarUnpack:
|
||||||
- resources/**
|
- resources/**
|
||||||
win:
|
win:
|
||||||
executableName: AIx
|
executableName: AIx
|
||||||
|
icon: resources/logo2.ico
|
||||||
nsis:
|
nsis:
|
||||||
oneClick: false
|
oneClick: false
|
||||||
allowToChangeInstallationDirectory: true
|
allowToChangeInstallationDirectory: true
|
||||||
|
@ -41,6 +42,6 @@ appImage:
|
||||||
npmRebuild: false
|
npmRebuild: false
|
||||||
publish:
|
publish:
|
||||||
provider: generic
|
provider: generic
|
||||||
url: https://example.com/auto-updates
|
url: https://file.ysaix.com:7868/src/assets/smarttalk/
|
||||||
electronDownload:
|
electronDownload:
|
||||||
mirror: https://npmmirror.com/mirrors/electron/
|
mirror: https://npmmirror.com/mirrors/electron/
|
||||||
|
|
|
@ -28,12 +28,7 @@ export default defineConfig({
|
||||||
// target: 'http://192.168.2.52:7863',
|
// target: 'http://192.168.2.52:7863',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (p) => p.replace(/^\/dev-api/, '')
|
rewrite: (p) => p.replace(/^\/dev-api/, '')
|
||||||
},
|
}
|
||||||
'/profile': {
|
|
||||||
target: 'http://192.168.2.52:7863',
|
|
||||||
ws: true,
|
|
||||||
changeOrigin: true
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [vue(), WindiCSS()],
|
plugins: [vue(), WindiCSS()],
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
"build": "electron-vite build",
|
"build": "electron-vite build",
|
||||||
"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:win": "npm run build && electron-builder --win",
|
"build:test": "npm run build && electron-builder --win --config ./electron-builder-test.yml",
|
||||||
|
"build:prod": "npm run build && electron-builder --win --config ./electron-builder.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"
|
||||||
},
|
},
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
"@vueuse/core": "^10.11.0",
|
"@vueuse/core": "^10.11.0",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"electron-dl-manager": "^3.0.0",
|
"electron-dl-manager": "^3.0.0",
|
||||||
|
"electron-log": "^5.1.7",
|
||||||
"electron-updater": "^6.1.7",
|
"electron-updater": "^6.1.7",
|
||||||
"element-plus": "^2.7.6",
|
"element-plus": "^2.7.6",
|
||||||
"fabric": "5.3.0",
|
"fabric": "5.3.0",
|
||||||
|
@ -31,8 +33,10 @@
|
||||||
"jsencrypt": "^3.3.2",
|
"jsencrypt": "^3.3.2",
|
||||||
"jsondiffpatch": "0.6.0",
|
"jsondiffpatch": "0.6.0",
|
||||||
"pdfjs-dist": "^4.4.168",
|
"pdfjs-dist": "^4.4.168",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"pinia-plugin-persistedstate": "^3.2.1",
|
"pinia-plugin-persistedstate": "^3.2.1",
|
||||||
|
"spark-md5": "^3.0.2",
|
||||||
"vue-cropper": "^1.0.3",
|
"vue-cropper": "^1.0.3",
|
||||||
"vue-router": "^4.4.0"
|
"vue-router": "^4.4.0"
|
||||||
},
|
},
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 264 KiB |
Binary file not shown.
After Width: | Height: | Size: 264 KiB |
197
src/main/file.js
197
src/main/file.js
|
@ -1,16 +1,105 @@
|
||||||
import CryptoJS from 'crypto-js'
|
import SparkMD5 from 'spark-md5'
|
||||||
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
import { ElectronDownloadManager } from 'electron-dl-manager'
|
import { ElectronDownloadManager } from 'electron-dl-manager'
|
||||||
import { dialog } from 'electron'
|
import { dialog } from 'electron'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
const uploadUrl = import.meta.env.VITE_APP_UPLOAD_API + '/smarttalk/file/upload'
|
const uploadUrl = import.meta.env.VITE_APP_UPLOAD_API + '/smarttalk/file/upload'
|
||||||
|
const asyncUploadUrl = import.meta.env.VITE_APP_UPLOAD_API + '/smarttalk/file/asyncUpload'
|
||||||
const manager = new ElectronDownloadManager()
|
const manager = new ElectronDownloadManager()
|
||||||
export default async function ({ app, shell, BrowserWindow, ipcMain }) {
|
export default async function ({ app, shell, BrowserWindow, ipcMain }) {
|
||||||
const userDataPath = app.getPath('userData')
|
const userDataPath = app.getPath('userData')
|
||||||
const appRootFilePath = userDataPath + '\\selfFile\\'
|
const appRootFilePath = userDataPath + '\\selfFile\\'
|
||||||
const appTempFilePath = userDataPath + '\\tempFile\\'
|
const appTempFilePath = userDataPath + '\\tempFile\\'
|
||||||
|
let Spark = new SparkMD5.ArrayBuffer()
|
||||||
|
|
||||||
|
ipcMain.on('upload-file-change', (e, { id, fileNewName, cookie, fileType }) => {
|
||||||
|
let filePath = appRootFilePath + fileNewName
|
||||||
|
//执行更新,上传文件
|
||||||
|
let formData = new FormData()
|
||||||
|
formData.append('id', id)
|
||||||
|
uploadFileByFS({
|
||||||
|
url: asyncUploadUrl,
|
||||||
|
path: filePath,
|
||||||
|
name: fileNewName,
|
||||||
|
cookie,
|
||||||
|
fileType,
|
||||||
|
formData,
|
||||||
|
success: (response) => {
|
||||||
|
e.reply('upload-file-change-success' + fileNewName, {
|
||||||
|
data: response.data,
|
||||||
|
md5: formData.md5
|
||||||
|
})
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
console.error('Error uploading file:', err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/*监听文件改变,如果有改变则返回触发*/
|
||||||
|
ipcMain.on('listen-file-change', (e, { id, fileNewName, md5, cookie, fileType }) => {
|
||||||
|
let filePath = appRootFilePath + fileNewName
|
||||||
|
let uploadId = null
|
||||||
|
let isOn = false
|
||||||
|
setInterval(() => {
|
||||||
|
getFileMD5(filePath).then((md5New) => {
|
||||||
|
if (md5New !== md5) {
|
||||||
|
md5 = md5New
|
||||||
|
if (uploadId) {
|
||||||
|
clearTimeout(uploadId)
|
||||||
|
}
|
||||||
|
if (isOn === false) {
|
||||||
|
e.reply('listen-file-change-on' + fileNewName)
|
||||||
|
isOn = true
|
||||||
|
}
|
||||||
|
//倒数十秒提交更改,十秒之内有继续修改则重置倒数
|
||||||
|
uploadId = setTimeout(() => {
|
||||||
|
//执行更新,上传文件
|
||||||
|
let formData = new FormData()
|
||||||
|
formData.append('id', id)
|
||||||
|
uploadFileByFS({
|
||||||
|
url: asyncUploadUrl,
|
||||||
|
path: filePath,
|
||||||
|
name: fileNewName,
|
||||||
|
cookie,
|
||||||
|
fileType,
|
||||||
|
formData,
|
||||||
|
success: (response) => {
|
||||||
|
e.reply('listen-file-change-success' + fileNewName, {
|
||||||
|
data: response.data,
|
||||||
|
md5: formData.md5
|
||||||
|
})
|
||||||
|
clearTimeout(uploadId)
|
||||||
|
isOn = false
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
console.error('Error uploading file:', err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 5000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 1000)
|
||||||
|
})
|
||||||
|
|
||||||
|
function getFileMD5(path) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fs.readFile(path, (err, dataFile) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
return console.error(err)
|
||||||
|
}
|
||||||
|
Spark.append(dataFile)
|
||||||
|
let md5 = Spark.end()
|
||||||
|
resolve(md5)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 判断是否有本地文件
|
||||||
|
* */
|
||||||
ipcMain.on('is-have-local-file', (e, fileNewName) => {
|
ipcMain.on('is-have-local-file', (e, fileNewName) => {
|
||||||
let filePath = appRootFilePath + fileNewName
|
let filePath = appRootFilePath + fileNewName
|
||||||
fs.access(filePath, fs.constants.F_OK, (err) => {
|
fs.access(filePath, fs.constants.F_OK, (err) => {
|
||||||
|
@ -21,10 +110,39 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
|
||||||
e.reply('is-have-local-file-reply' + fileNewName, true)
|
e.reply('is-have-local-file-reply' + fileNewName, true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 判断是需要同步本地文件
|
||||||
|
* */
|
||||||
|
ipcMain.on('is-async-local-file', (e, { fileNewName, lastModifyTime, md5 }) => {
|
||||||
|
let filePath = appRootFilePath + fileNewName
|
||||||
|
fs.access(filePath, fs.constants.F_OK, (err) => {
|
||||||
|
if (err) {
|
||||||
|
e.reply('is-async-local-file-reply' + fileNewName, { isAsync: true, type: 'down' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
getFileMD5(filePath).then((localMd5) => {
|
||||||
|
if (localMd5 === md5) {
|
||||||
|
e.reply('is-async-local-file-reply' + fileNewName, { isAsync: false, type: '' })
|
||||||
|
} else {
|
||||||
|
const stats = fs.statSync(filePath)
|
||||||
|
//如果线上时间大于线下时间,就需要从线上下载,否则则需要上传
|
||||||
|
let time = new Date(lastModifyTime)
|
||||||
|
if (time > stats.mtime.getTime()) {
|
||||||
|
e.reply('is-async-local-file-reply' + fileNewName, { isAsync: true, type: 'down' })
|
||||||
|
} else if (time < stats.mtime.getTime()) {
|
||||||
|
e.reply('is-async-local-file-reply' + fileNewName, { isAsync: true, type: 'upload' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
//默认浏览器打开url
|
//默认浏览器打开url
|
||||||
ipcMain.on('open-url-browser', (e, url) => {
|
ipcMain.on('open-url-browser', (e, url) => {
|
||||||
shell.openPath(url)
|
shell.openPath(url)
|
||||||
})
|
})
|
||||||
|
|
||||||
//使用默认应用打开本地文件
|
//使用默认应用打开本地文件
|
||||||
ipcMain.on('open-path-app', (e, destination) => {
|
ipcMain.on('open-path-app', (e, destination) => {
|
||||||
let path = appRootFilePath + destination
|
let path = appRootFilePath + destination
|
||||||
|
@ -40,30 +158,14 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
//复制文件
|
//导出文件
|
||||||
ipcMain.on('export-file-default', (e, list) => {
|
ipcMain.on('export-file-default', (e, list) => {
|
||||||
exportFile(list, (res) => {
|
exportFile(list, (res) => {
|
||||||
e.reply('export-file-default-reply', res)
|
e.reply('export-file-default-reply', res)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
function getFileMD5(file) {
|
function uploadFileByFS({ url, path, name, cookie, fileType, formData, success, error }) {
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const fileReader = new FileReader()
|
|
||||||
fileReader.onload = (e) => {
|
|
||||||
const buffer = e.target.result
|
|
||||||
let md5 = CryptoJS.MD5(buffer).toString()
|
|
||||||
resolve(md5)
|
|
||||||
}
|
|
||||||
fileReader.readAsArrayBuffer(file)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
ipcMain.on('creat-file-default', (e, { name, uploadData, cookie }) => {
|
|
||||||
createFolder('tempFile').then(() => {
|
|
||||||
let path = appTempFilePath + name
|
|
||||||
fs.writeFileSync(path, '', 'utf-8')
|
|
||||||
// 读取文件
|
|
||||||
fs.readFile(path, (err, data) => {
|
fs.readFile(path, (err, data) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return console.error(err)
|
return console.error(err)
|
||||||
|
@ -75,30 +177,55 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
|
||||||
Authorization: 'Bearer ' + cookie
|
Authorization: 'Bearer ' + cookie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let md5 = CryptoJS.MD5(data).toString()
|
Spark.append(data)
|
||||||
let formData = new FormData()
|
let md5 = Spark.end()
|
||||||
// 使用axios上传文件
|
// 使用axios上传文件
|
||||||
let file = new File([data], name, {
|
let file = new File([data], name, {
|
||||||
type: 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
|
type: fileType
|
||||||
})
|
})
|
||||||
|
const stats = fs.statSync(path)
|
||||||
formData.append('file', file)
|
formData.append('file', file)
|
||||||
formData.append('md5', md5)
|
formData.append('md5', md5)
|
||||||
|
formData.append('lastModifyTime', stats.mtime.toLocaleString())
|
||||||
|
axios
|
||||||
|
.post(url, formData, config)
|
||||||
|
.then((response) => {
|
||||||
|
success(response)
|
||||||
|
})
|
||||||
|
.catch((errorMsg) => {
|
||||||
|
error(errorMsg)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*创建新的ppt文件*/
|
||||||
|
ipcMain.on('creat-file-default', (e, { name, uploadData, cookie }) => {
|
||||||
|
createFolder('tempFile').then(() => {
|
||||||
|
let path = appTempFilePath + name
|
||||||
|
fs.writeFileSync(path, '', 'utf-8')
|
||||||
|
let fileType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
|
||||||
|
let formData = new FormData()
|
||||||
for (let key in uploadData) {
|
for (let key in uploadData) {
|
||||||
if (uploadData.hasOwnProperty(key)) { // 检查是否是对象自身的属性
|
if (Object.prototype.hasOwnProperty.call(uploadData, key)) {
|
||||||
|
// 检查是否是对象自身的属性
|
||||||
formData.append(key, uploadData[key])
|
formData.append(key, uploadData[key])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
formData.append("fileFlag","教案")
|
formData.append('fileFlag', '教案')
|
||||||
axios
|
uploadFileByFS({
|
||||||
.post(uploadUrl, formData, config)
|
url: uploadUrl,
|
||||||
.then((response) => {
|
path,
|
||||||
|
name,
|
||||||
|
cookie,
|
||||||
|
fileType,
|
||||||
|
formData,
|
||||||
|
success: (response) => {
|
||||||
e.reply('creat-file-default-reply', response.data)
|
e.reply('creat-file-default-reply', response.data)
|
||||||
console.log('File uploaded successfully:', response.data)
|
console.log('File uploaded successfully:', response.data)
|
||||||
})
|
},
|
||||||
.catch((error) => {
|
error: (err) => {
|
||||||
console.error('Error uploading file:', error)
|
console.error('Error uploading file:', err)
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -191,6 +318,7 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/*导出文件*/
|
||||||
function exportFile(list, callback) {
|
function exportFile(list, callback) {
|
||||||
let win = BrowserWindow.getFocusedWindow()
|
let win = BrowserWindow.getFocusedWindow()
|
||||||
//通过扩展名识别文件类型
|
//通过扩展名识别文件类型
|
||||||
|
@ -220,10 +348,12 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*文件是否已经存在*/
|
||||||
function isHaveFile(path) {
|
function isHaveFile(path) {
|
||||||
return fs.existsSync(path)
|
return fs.existsSync(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*判断是否已经存在这个名字的文件,如果已经存在则递增导出*/
|
||||||
function filterCopyFile(path, index = 0) {
|
function filterCopyFile(path, index = 0) {
|
||||||
if (isHaveFile(path) === true) {
|
if (isHaveFile(path) === true) {
|
||||||
index++
|
index++
|
||||||
|
@ -234,6 +364,7 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*复制文件*/
|
||||||
function copyRelFile(source, destination, callback) {
|
function copyRelFile(source, destination, callback) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const readStream = fs.createReadStream(source)
|
const readStream = fs.createReadStream(source)
|
||||||
|
@ -256,6 +387,7 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*复制文件*/
|
||||||
function copyFile(source, destination, callback) {
|
function copyFile(source, destination, callback) {
|
||||||
let path = appRootFilePath + destination
|
let path = appRootFilePath + destination
|
||||||
createFolder('selfFile').then(() => {
|
createFolder('selfFile').then(() => {
|
||||||
|
@ -276,6 +408,7 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*创建文件夹*/
|
||||||
function createFolder(folderName) {
|
function createFolder(folderName) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const folderPath = path.join(userDataPath, folderName)
|
const folderPath = path.join(userDataPath, folderName)
|
||||||
|
|
|
@ -8,11 +8,10 @@ import File from './file'
|
||||||
import remote from '@electron/remote/main'
|
import remote from '@electron/remote/main'
|
||||||
// 第二步: 初始化remote
|
// 第二步: 初始化remote
|
||||||
remote.initialize()
|
remote.initialize()
|
||||||
|
import updateInit from './update'
|
||||||
|
|
||||||
File({ app, shell, BrowserWindow, ipcMain })
|
File({ app, shell, BrowserWindow, ipcMain })
|
||||||
|
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
|
||||||
|
|
||||||
|
|
||||||
let mainWindow, loginWindow
|
let mainWindow, loginWindow
|
||||||
|
|
||||||
//登录窗口
|
//登录窗口
|
||||||
|
@ -24,6 +23,7 @@ function createLoginWindow() {
|
||||||
show: false,
|
show: false,
|
||||||
frame: false,
|
frame: false,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
|
icon: join(__dirname, '../../resources/logo2.ico'),
|
||||||
...(process.platform === 'linux' ? { icon } : {}),
|
...(process.platform === 'linux' ? { icon } : {}),
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: join(__dirname, '../preload/index.js'),
|
preload: join(__dirname, '../preload/index.js'),
|
||||||
|
@ -31,9 +31,17 @@ function createLoginWindow() {
|
||||||
nodeIntegration: true
|
nodeIntegration: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const loginURL = is.dev ? `http://localhost:5173/#/login` : `file://${__dirname}/index.html/login`
|
// handleUpdate(loginWindow,ipcMain)
|
||||||
loginWindow.loadURL(loginURL)
|
// const loginURL = is.dev ? `http://localhost:5173/#/login` : `file://${__dirname}/index.html/#/login`
|
||||||
|
// loginWindow.loadURL(loginURL)
|
||||||
|
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
|
||||||
|
loginWindow.loadURL('http://localhost:5173/#/login')
|
||||||
|
} else {
|
||||||
|
loginWindow.loadFile(join(__dirname, '../renderer/index.html'), {hash: 'login'})
|
||||||
|
updateInit(loginWindow)
|
||||||
|
}
|
||||||
|
|
||||||
|
// loginWindow.webContents.openDevTools()
|
||||||
loginWindow.once('ready-to-show', () => {
|
loginWindow.once('ready-to-show', () => {
|
||||||
loginWindow.show()
|
loginWindow.show()
|
||||||
})
|
})
|
||||||
|
@ -48,8 +56,9 @@ function createMainWindow() {
|
||||||
width: 1200,
|
width: 1200,
|
||||||
height: 700,
|
height: 700,
|
||||||
show: false,
|
show: false,
|
||||||
frame: false,
|
frame: false, // 无边框
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
|
icon: join(__dirname, '../../resources/logo2.ico'),
|
||||||
...(process.platform === 'linux' ? { icon } : {}),
|
...(process.platform === 'linux' ? { icon } : {}),
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: join(__dirname, '../preload/index.js'),
|
preload: join(__dirname, '../preload/index.js'),
|
||||||
|
@ -84,47 +93,41 @@ function createMainWindow() {
|
||||||
remote.enable(mainWindow.webContents)
|
remote.enable(mainWindow.webContents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 作业窗口相关-开发中
|
// 作业窗口相关-开发中
|
||||||
let workWindow
|
let linkWindow
|
||||||
function createWork(data) {
|
async function createLinkWin(data) {
|
||||||
if (workWindow) return
|
if (linkWindow) return
|
||||||
workWindow = new BrowserWindow({
|
linkWindow = new BrowserWindow({
|
||||||
width: 650,
|
width: 650,
|
||||||
height: 500,
|
height: 500,
|
||||||
show: false,
|
show: false,
|
||||||
frame: true,
|
frame: true,
|
||||||
|
maximizable: true,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
...(process.platform === 'linux' ? { icon } : {}),
|
...(process.platform === 'linux' ? { icon } : {}),
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
sandbox: false,
|
sandbox: false,
|
||||||
nodeIntegration: true
|
nodeIntegration: true,
|
||||||
|
worldSafeExecuteJavaScript: true,
|
||||||
|
contextIsolation: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
let cookieDetails = { ...data.cookieData }
|
||||||
workWindow.webContents.session.cookies.set(
|
await linkWindow.webContents.session.cookies.set(cookieDetails).then(()=>{
|
||||||
{
|
console.log('Cookie is successful');
|
||||||
url: 'https://file.ysaix.com:7868',
|
}).catch( error =>{
|
||||||
name: 'Admin-Token',
|
console.error('Cookie is error', error);
|
||||||
value: data
|
|
||||||
},
|
|
||||||
function (error) {
|
|
||||||
if (error) {
|
|
||||||
console.error('Set cookie failed:', error)
|
|
||||||
} else {
|
|
||||||
console.log('Cookie set successfully.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
workWindow.loadURL(
|
|
||||||
'https://file.ysaix.com:7868/teaching/classtaskassign?titleName=%E4%BD%9C%E4%B8%9A%E5%B8%83%E7%BD%AE'
|
|
||||||
)
|
|
||||||
|
|
||||||
workWindow.once('ready-to-show', () => {
|
|
||||||
workWindow.show()
|
|
||||||
})
|
})
|
||||||
workWindow.on('closed', () => {
|
|
||||||
workWindow = null
|
linkWindow.loadURL(data.fullPath)
|
||||||
|
|
||||||
|
linkWindow.once('ready-to-show', () => {
|
||||||
|
linkWindow.show()
|
||||||
|
linkWindow.maximize()
|
||||||
|
})
|
||||||
|
linkWindow.on('closed', () => {
|
||||||
|
linkWindow = null
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,17 +178,19 @@ app.on('ready', () => {
|
||||||
createLoginWindow()
|
createLoginWindow()
|
||||||
}
|
}
|
||||||
mainWindow.destroy()
|
mainWindow.destroy()
|
||||||
|
mainWindow = null
|
||||||
loginWindow.show()
|
loginWindow.show()
|
||||||
loginWindow.focus()
|
loginWindow.focus()
|
||||||
})
|
})
|
||||||
|
|
||||||
//打开作业窗口
|
//打开作业窗口
|
||||||
ipcMain.on('openWork', (e, data) => {
|
ipcMain.on('openWindow', (e, data) => {
|
||||||
createWork(data)
|
createLinkWin(data)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 打开-登录窗口
|
// 打开-登录窗口
|
||||||
createLoginWindow()
|
createLoginWindow()
|
||||||
|
|
||||||
app.on('activate', function () {
|
app.on('activate', function () {
|
||||||
if (BrowserWindow.getAllWindows().length === 0) createLoginWindow()
|
if (BrowserWindow.getAllWindows().length === 0) createLoginWindow()
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { dialog } from 'electron'
|
||||||
|
import logger from 'electron-log'
|
||||||
|
const updateURL = 'http://27.128.240.72:3000/zhuhao/AIx_Smarttalk/releases/tag/V1.0.0%28%E6%B5%8B%E8%AF%95%E7%89%88%29/'
|
||||||
|
|
||||||
|
// 主进程中的更新检查
|
||||||
|
const { autoUpdater } = require('electron-updater')
|
||||||
|
|
||||||
|
const updateInit = (win) => {
|
||||||
|
logger.info('进来了')
|
||||||
|
// 检查更新
|
||||||
|
autoUpdater.checkForUpdates()
|
||||||
|
// 自动下载
|
||||||
|
autoUpdater.autoDownload = false
|
||||||
|
// 设置版本更新服务器地址
|
||||||
|
// autoUpdater.setFeedURL(updateURL)
|
||||||
|
|
||||||
|
//监听更新事件
|
||||||
|
autoUpdater.on('update-available', (info) => {
|
||||||
|
logger.info('发现新版本')
|
||||||
|
dialog
|
||||||
|
.showMessageBox(win,{
|
||||||
|
type: 'info',
|
||||||
|
title: '新版本可用',
|
||||||
|
message: '有一个可用的新版本,要更新吗',
|
||||||
|
buttons: ['是', '否']
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
if (result.response === 0) {
|
||||||
|
// 用户选择更新,触发下载和安装
|
||||||
|
autoUpdater.downloadUpdate()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 没有新版本
|
||||||
|
autoUpdater.on('update-not-available', () => {
|
||||||
|
logger.info('没有新版本')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 更新发生错误
|
||||||
|
autoUpdater.on('error', () => {
|
||||||
|
logger.error('检查更新失败')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 跟新下载完毕
|
||||||
|
autoUpdater.on('update-downloaded', () => {
|
||||||
|
dialog
|
||||||
|
.showMessageBox({
|
||||||
|
type: 'info',
|
||||||
|
title: '更新下载完成',
|
||||||
|
message: '点击确定重启获取最新内容',
|
||||||
|
buttons: ['确定']
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// 调用 quitAndInstall 来安装更新
|
||||||
|
autoUpdater.quitAndInstall()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default updateInit
|
|
@ -9,6 +9,13 @@ export const getSmarttalkPage = (params) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getPrepareById = (id) => {
|
||||||
|
return request({
|
||||||
|
url: '/smarttalk/file/' + id,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function deleteSmarttalk(id) {
|
export function deleteSmarttalk(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/smarttalk/file/' + id,
|
url: '/smarttalk/file/' + id,
|
||||||
|
|
|
@ -64,6 +64,8 @@ const defaultProps = {
|
||||||
const curBookId = ref(-1)
|
const curBookId = ref(-1)
|
||||||
//当前教材名称
|
//当前教材名称
|
||||||
const curBookName = ref('')
|
const curBookName = ref('')
|
||||||
|
//当前教材封面图
|
||||||
|
const curBookImg = ref('')
|
||||||
// 上册
|
// 上册
|
||||||
const volumeOne = ref([])
|
const volumeOne = ref([])
|
||||||
// 下册
|
// 下册
|
||||||
|
@ -110,9 +112,10 @@ const getSubjectContent = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
//选择教材
|
//选择教材
|
||||||
const changeBook = ({ id, itemtitle }) => {
|
const changeBook = ({ id, itemtitle, avartar }) => {
|
||||||
curBookId.value = id
|
curBookId.value = id
|
||||||
curBookName.value = itemtitle
|
curBookName.value = itemtitle
|
||||||
|
curBookImg.value = BaseUrl + avartar
|
||||||
getTreeData()
|
getTreeData()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
|
@ -144,7 +147,8 @@ const emitChangeBook = () => {
|
||||||
const data = {
|
const data = {
|
||||||
textBook: {
|
textBook: {
|
||||||
curBookId: curBookId.value,
|
curBookId: curBookId.value,
|
||||||
curBookName: curBookName.value
|
curBookName: curBookName.value,
|
||||||
|
curBookImg: curBookImg.value
|
||||||
},
|
},
|
||||||
node: curNode
|
node: curNode
|
||||||
}
|
}
|
||||||
|
@ -236,6 +240,7 @@ const getSubject = async () => {
|
||||||
// 默认第一个
|
// 默认第一个
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -264,7 +269,8 @@ const handleNodeClick = (data, node) => {
|
||||||
let curData = {
|
let curData = {
|
||||||
textBook: {
|
textBook: {
|
||||||
curBookId: curBookId.value,
|
curBookId: curBookId.value,
|
||||||
curBookName: curBookName.value
|
curBookName: curBookName.value,
|
||||||
|
curBookImg: curBookImg.value
|
||||||
},
|
},
|
||||||
node: toRaw(currentNode)
|
node: toRaw(currentNode)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,27 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="canvasitem">
|
<div class="canvasitem">
|
||||||
<canvas v-for="(item,index) in pdfObj.numberOfPdf" :key="index" :id="'pdf-canvas'+(index+1)" :ref="'canvasPdf'+(index+1)" class="pdf-canvas" style="height:100vh;padding-right:10px"></canvas>
|
<div class="pdfAdnFabric">
|
||||||
|
<canvas id="pdf-fabric"></canvas>
|
||||||
|
<canvas id="pdf-fabric1" v-if="props.pdfObj.numberOfPdf == 2"></canvas>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup >
|
<script setup >
|
||||||
import { ref, onMounted, watch, reactive,defineProps ,defineExpose,nextTick,defineEmits } from 'vue';
|
import {
|
||||||
|
ref,
|
||||||
|
onMounted,
|
||||||
|
watch,
|
||||||
|
reactive,
|
||||||
|
defineProps,
|
||||||
|
defineExpose,
|
||||||
|
nextTick,
|
||||||
|
defineEmits
|
||||||
|
} from 'vue'
|
||||||
|
import { fabric } from 'fabric'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { handleevent, savecanvsStore, initcanvasdata, displayData } from '@/utils/pdfAndFabric'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
pdfObj: {
|
pdfObj: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -16,75 +32,166 @@ const props = defineProps({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const numPages=ref(0)
|
// canvas的所有数据
|
||||||
|
const canvsStore = reactive({
|
||||||
|
id: 'xxxx',
|
||||||
|
pageArr: []
|
||||||
|
})
|
||||||
|
const fabriccanvas = ref(null)
|
||||||
|
const fabriccanvas1 = ref(null)
|
||||||
|
// 页面总数
|
||||||
|
const numPagesTotal = ref(0)
|
||||||
|
const imgarr = ref([])
|
||||||
// 多个pdf的对象
|
// 多个pdf的对象
|
||||||
const canvasNumbsValue = ref([]);
|
const canvasNumbsValue = ref([])
|
||||||
const emit = defineEmits(['update:numPages'])
|
const emit = defineEmits(['update:numPagesTotal'])
|
||||||
const renderPage = async (canvasobj) => {
|
const renderPage = async (canvasobj) => {
|
||||||
if(canvasobj.page>numPages.value) return
|
if (canvasobj.page > numPagesTotal.value) return
|
||||||
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise;
|
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise
|
||||||
// 渲染当前页
|
// 渲染当前页
|
||||||
const page1 = await pdf.getPage(canvasobj.page);
|
const page = await pdf.getPage(canvasobj.page)
|
||||||
const viewport1 = page1.getViewport({ scale: 1 });
|
const viewport = page.getViewport({ scale: 1 })
|
||||||
const canvasElement1 = canvasobj.canvas;
|
|
||||||
canvasElement1.width = viewport1.width;
|
|
||||||
canvasElement1.height = viewport1.height;
|
|
||||||
|
|
||||||
const renderContext1 = {
|
const canvasElement = canvasobj.canvas
|
||||||
|
canvasElement.width = viewport.width
|
||||||
|
canvasElement.height = viewport.height
|
||||||
|
const renderContext = {
|
||||||
canvasContext: canvasobj.context,
|
canvasContext: canvasobj.context,
|
||||||
viewport: viewport1,
|
viewport: viewport
|
||||||
};
|
}
|
||||||
await page1.render(renderContext1).promise;
|
page.render(renderContext).promise.then((res) => {
|
||||||
|
const img = document.createElement('img')
|
||||||
};
|
img.src = canvasobj.canvas.toDataURL('image/png')
|
||||||
|
canvasobj.canvas.remove()
|
||||||
|
imgarr.value.push({ src: img.src, page: canvasobj.page, JSONdata: {}, index: canvasobj.index })
|
||||||
|
img.onload = () => {
|
||||||
|
// 在这里执行图像加载完成后的操作
|
||||||
|
// 根据传过来的pdf对象 判断改渲染哪一个fabric
|
||||||
|
if (props.pdfObj.numberOfPdf == 2) {
|
||||||
|
if (canvasobj.index == 0) {
|
||||||
|
fabriccanvas.value.setWidth(img.width)
|
||||||
|
fabriccanvas.value.setHeight(img.height)
|
||||||
|
displayData(fabriccanvas, canvsStore, canvasobj, fabric, img)
|
||||||
|
} else {
|
||||||
|
fabriccanvas1.value.setWidth(img.width)
|
||||||
|
fabriccanvas1.value.setHeight(img.height)
|
||||||
|
displayData(fabriccanvas1, canvsStore, canvasobj, fabric, img)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fabriccanvas.value.setWidth(img.width)
|
||||||
|
fabriccanvas.value.setHeight(img.height)
|
||||||
|
displayData(fabriccanvas, canvsStore, canvasobj, fabric, img)
|
||||||
|
}
|
||||||
|
// console.log(imgarr.value)
|
||||||
|
img.remove()
|
||||||
|
}
|
||||||
|
// 判断imgarr的JSONdata在canvsStore.pageArr有没有
|
||||||
|
canvsStore.pageArr.forEach((item) => {
|
||||||
|
if (item.page == canvasobj.page) {
|
||||||
|
imgarr.value.forEach((img) => {
|
||||||
|
if (img.page == canvasobj.page) {
|
||||||
|
img.JSONdata = item.JSONdata
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
const updatePage = (canvasobj) => {
|
const updatePage = (canvasobj) => {
|
||||||
renderPage(canvasobj);
|
renderPage(canvasobj)
|
||||||
};
|
}
|
||||||
const loadPdf = async (canvasobj) => {
|
const loadPdf = async (canvasobj) => {
|
||||||
|
updatePage(canvasobj)
|
||||||
|
}
|
||||||
|
|
||||||
updatePage(canvasobj);
|
const initPdf = async (type = 'default') => {
|
||||||
|
// 保存数据
|
||||||
};
|
savecanvsStore(imgarr, canvsStore)
|
||||||
const initPdf = async() => {
|
// initcanvasdata(fabriccanvas)
|
||||||
|
// initcanvasdata(fabriccanvas1)
|
||||||
|
// 单页模式
|
||||||
|
if (type == 'restone') {
|
||||||
|
// 清除 canvas 上的所有对象
|
||||||
|
fabriccanvas1.value.clear()
|
||||||
|
// 释放 canvas 的资源
|
||||||
|
fabriccanvas1.value.dispose()
|
||||||
|
}
|
||||||
// 清除现有 canvas 元素的内容
|
// 清除现有 canvas 元素的内容
|
||||||
canvasNumbsValue.value.forEach((canvasObj) => {
|
canvasNumbsValue.value.forEach((canvasObj) => {
|
||||||
const context = canvasObj.context;
|
const context = canvasObj.context
|
||||||
context.clearRect(0, 0, canvasObj.canvas.width, canvasObj.canvas.height);
|
context.clearRect(0, 0, canvasObj.canvas.width, canvasObj.canvas.height)
|
||||||
});
|
})
|
||||||
|
// 清除所有对象
|
||||||
|
imgarr.value = []
|
||||||
canvasNumbsValue.value = []
|
canvasNumbsValue.value = []
|
||||||
if (props.pdfObj.pdfUrl) {
|
if (props.pdfObj.pdfUrl) {
|
||||||
await nextTick(); // 确保 DOM 渲染完成
|
await nextTick() // 确保 DOM 渲染完成
|
||||||
if (props.pdfObj.numberOfPdf == 1) {
|
if (props.pdfObj.numberOfPdf == 1) {
|
||||||
canvasNumbsValue.value = [{}]
|
canvasNumbsValue.value = [{}]
|
||||||
canvasNumbsValue.value[0].canvas = document.getElementById('pdf-canvas1');
|
const canvasElement = document.createElement('canvas')
|
||||||
canvasNumbsValue.value[0].context = canvasNumbsValue.value[0].canvas.getContext('2d');
|
canvasNumbsValue.value[0].canvas = canvasElement
|
||||||
canvasNumbsValue.value[0].page =Number(props.pdfObj.numPages)*props.pdfObj.numberOfPdf
|
canvasNumbsValue.value[0].context = canvasNumbsValue.value[0].canvas.getContext('2d')
|
||||||
await loadPdf(canvasNumbsValue.value[0]);
|
canvasNumbsValue.value[0].page = props.pdfObj.numPages
|
||||||
|
canvasNumbsValue.value[0].index = 0
|
||||||
|
await loadPdf(canvasNumbsValue.value[0])
|
||||||
} else {
|
} else {
|
||||||
for (var i = 0; i < props.pdfObj.numberOfPdf; i++) {
|
for (var i = 0; i < props.pdfObj.numberOfPdf; i++) {
|
||||||
canvasNumbsValue.value[i] = {};
|
canvasNumbsValue.value[i] = {}
|
||||||
canvasNumbsValue.value[i].canvas = document.getElementById('pdf-canvas'+(i+1));
|
const canvasElement = document.createElement('canvas')
|
||||||
canvasNumbsValue.value[i].context = canvasNumbsValue.value[i].canvas.getContext('2d');
|
canvasNumbsValue.value[i].canvas = canvasElement
|
||||||
|
canvasNumbsValue.value[i].context = canvasNumbsValue.value[i].canvas.getContext('2d')
|
||||||
|
// 设置页数
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
canvasNumbsValue.value[i].page =Number(props.pdfObj.numPages)*props.pdfObj.numberOfPdf-1
|
canvasNumbsValue.value[i].page = props.pdfObj.numPages
|
||||||
} else {
|
} else {
|
||||||
canvasNumbsValue.value[i].page =Number(props.pdfObj.numPages)*props.pdfObj.numberOfPdf
|
canvasNumbsValue.value[i].page = props.pdfObj.numPages + 1
|
||||||
}
|
|
||||||
await loadPdf(canvasNumbsValue.value[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canvasNumbsValue.value[i].index = i
|
||||||
|
// 加载FabricVue
|
||||||
|
await loadPdf(canvasNumbsValue.value[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const initPdfone = async () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
fabriccanvas1.value = new fabric.Canvas('pdf-fabric1')
|
||||||
|
fabriccanvas1.value.isDrawingMode = true
|
||||||
|
fabriccanvas1.value.freeDrawingBrush.color = 'red'
|
||||||
|
fabriccanvas1.value.setWidth(595)
|
||||||
|
}, 0)
|
||||||
|
initPdf('addOnePage')
|
||||||
|
}
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise;
|
try {
|
||||||
numPages.value = pdf.numPages;
|
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise
|
||||||
emit('update:numPages', pdf.numPages);
|
numPagesTotal.value = pdf.numPages
|
||||||
|
// console.log(pdf)
|
||||||
|
// 初始化fabriccanvas
|
||||||
|
fabriccanvas.value = new fabric.Canvas('pdf-fabric')
|
||||||
|
fabriccanvas.value.setWidth(595)
|
||||||
|
fabriccanvas.value.isDrawingMode = true
|
||||||
|
fabriccanvas.value.freeDrawingBrush.color = 'red'
|
||||||
|
|
||||||
|
fabriccanvas1.value = new fabric.Canvas('pdf-fabric1')
|
||||||
|
fabriccanvas1.value.isDrawingMode = true
|
||||||
|
fabriccanvas1.value.freeDrawingBrush.color = 'red'
|
||||||
|
fabriccanvas1.value.setWidth(595)
|
||||||
|
emit('update:numPagesTotal', pdf.numPages)
|
||||||
initPdf()
|
initPdf()
|
||||||
});
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
ElMessage.error('pdf文件错误')
|
||||||
|
}
|
||||||
|
// 监听2个canvas事件
|
||||||
|
handleevent(fabriccanvas.value, imgarr)
|
||||||
|
handleevent(fabriccanvas1.value, imgarr, 'two')
|
||||||
|
})
|
||||||
defineExpose({
|
defineExpose({
|
||||||
initPdf
|
initPdf,
|
||||||
});
|
initPdfone
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -92,6 +199,15 @@ defineExpose({
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.pdfAdnFabric {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
height: 100vh;
|
||||||
|
align-items: center;
|
||||||
|
:deep(> div:nth-of-type(1)) {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -79,10 +79,6 @@ const subjectList = ref([])
|
||||||
const allSubject = ref([])
|
const allSubject = ref([])
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
|
|
||||||
watch(() => props.modelValue, (newVal) => {
|
|
||||||
dialogVisible.value = newVal
|
|
||||||
})
|
|
||||||
|
|
||||||
//切换年级
|
//切换年级
|
||||||
const changeGrade = ()=>{
|
const changeGrade = ()=>{
|
||||||
// 切换年级 过滤出对应学科数据
|
// 切换年级 过滤出对应学科数据
|
||||||
|
@ -120,8 +116,13 @@ const editUserInfo = async () =>{
|
||||||
emit('onSuccess')
|
emit('onSuccess')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(() => props.modelValue, (newVal) => {
|
||||||
|
dialogVisible.value = newVal
|
||||||
|
if(newVal){
|
||||||
|
getSubject()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(getSubject)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -138,11 +139,13 @@ onMounted(getSubject)
|
||||||
|
|
||||||
.dialog-content {
|
.dialog-content {
|
||||||
padding: 30px 20px 10px 30px;
|
padding: 30px 20px 10px 30px;
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-footer{
|
.dialog-footer{
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
<el-form>
|
<el-form>
|
||||||
<el-form-item label="文件">
|
<el-form-item label="文件">
|
||||||
<div class="create-item file-item flex">
|
<div class="create-item file-item flex">
|
||||||
<el-upload :file-list="fileList" :show-file-list="false" :auto-upload="false" multiple
|
<el-upload :file-list="fileList" :limit="limit" :show-file-list="false" :auto-upload="false" multiple
|
||||||
:on-change="hanleFileChange">
|
:on-change="hanleFileChange">
|
||||||
<el-button slot="trigger">选择文件</el-button>
|
<el-button slot="trigger">选择文件</el-button>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<span class="upload-desc">说明:一次最多上传5个文件,单个文件大小不能大于100M</span>
|
<span class="upload-desc">说明:一次最多上传{{ limit }}个文件,单个文件大小不能大于100M</span>
|
||||||
|
<span class="upload-desc">仅支持图片、音频、视频、word、ppt、pdf、txt、zip文件</span>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
|
@ -23,7 +24,8 @@
|
||||||
<div class="flex-type flex">
|
<div class="flex-type flex">
|
||||||
<span class="name">类别:</span>
|
<span class="name">类别:</span>
|
||||||
<el-select v-model="item.fileData.fileFlag" placeholder="Select" style="width: 100px">
|
<el-select v-model="item.fileData.fileFlag" placeholder="Select" style="width: 100px">
|
||||||
<el-option v-for="item in resourceType" :key="item.alue" :label="item.label" :value="item.value" />
|
<el-option v-for="el in resourceType" :key="el.alue" :label="el.label" :value="el.value"
|
||||||
|
:disabled="checkFile(el, item)" />
|
||||||
</el-select>
|
</el-select>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,6 +60,7 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const dialogValue = ref(false)
|
const dialogValue = ref(false)
|
||||||
|
const limit = ref(5)
|
||||||
// 定义要发送的emit事件
|
// 定义要发送的emit事件
|
||||||
const emit = defineEmits(['update:modelValue', 'submitFile'])
|
const emit = defineEmits(['update:modelValue', 'submitFile'])
|
||||||
// 文件列表
|
// 文件列表
|
||||||
|
@ -93,6 +96,8 @@ const hanleFileChange = (file) => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// 验证文件大小
|
// 验证文件大小
|
||||||
|
// B < KB < MB < GB
|
||||||
|
// file.raw.size 单位是B
|
||||||
const fileSize = file.raw.size / 1024 / 1024 > 100
|
const fileSize = file.raw.size / 1024 / 1024 > 100
|
||||||
if (fileSize) {
|
if (fileSize) {
|
||||||
ElMessage.error('文件大小错误! 请上传小于100M的文件!')
|
ElMessage.error('文件大小错误! 请上传小于100M的文件!')
|
||||||
|
@ -102,13 +107,28 @@ const hanleFileChange = (file) => {
|
||||||
|
|
||||||
// 给一个默认的fileData
|
// 给一个默认的fileData
|
||||||
file.fileData = {
|
file.fileData = {
|
||||||
fileFlag: '课件',
|
fileFlag: '素材',
|
||||||
name: getFileName(file.name),
|
name: getFileName(file.name),
|
||||||
}
|
}
|
||||||
fileList.value.push(file)
|
fileList.value.push(file)
|
||||||
|
console.log(fileList.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查文件类型
|
||||||
|
const checkFile = (item, file) => {
|
||||||
|
const type = file.raw.type
|
||||||
|
const pptTypes = ['application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation']
|
||||||
|
let isPpt = pptTypes.includes(type)
|
||||||
|
if(!isPpt && item.value == '教案'){
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
const delFile = (index) => {
|
const delFile = (index) => {
|
||||||
fileList.value.splice(index, 1)
|
fileList.value.splice(index, 1)
|
||||||
|
@ -203,11 +223,14 @@ const submitFile = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-input {
|
.file-input {
|
||||||
border-bottom: solid #dfdfdf 1px;
|
border-bottom: solid #dfdfdf 1px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: #409EFF;
|
border-color: #409EFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
border-color: #409EFF;
|
border-color: #409EFF;
|
||||||
}
|
}
|
||||||
|
@ -216,11 +239,12 @@ const submitFile = () => {
|
||||||
:deep(.el-input__wrapper) {
|
:deep(.el-input__wrapper) {
|
||||||
box-shadow: none
|
box-shadow: none
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-input__wrapper.is-focus) {
|
:deep(.el-input__wrapper.is-focus) {
|
||||||
box-shadow: none
|
box-shadow: none
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-input__wrapper:hover) {
|
:deep(.el-input__wrapper:hover) {
|
||||||
box-shadow: none
|
box-shadow: none
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -113,9 +113,6 @@ const emits = defineEmits(['setLayout'])
|
||||||
function setLayout() {
|
function setLayout() {
|
||||||
emits('setLayout');
|
emits('setLayout');
|
||||||
}
|
}
|
||||||
watch(()=> userStore.avatar,() => {
|
|
||||||
userImg.value = userStore.avatar;
|
|
||||||
},{deep:true})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -24,7 +24,8 @@
|
||||||
<div class="prepare-body-main-item">
|
<div class="prepare-body-main-item">
|
||||||
<div class="prepare-uploader-progress" :style="{ width: item.percentage + '%' }"></div>
|
<div class="prepare-uploader-progress" :style="{ width: item.percentage + '%' }"></div>
|
||||||
<div class="prepare-body-main-item-icon">
|
<div class="prepare-body-main-item-icon">
|
||||||
<svg
|
<FileImage :size="50" :file-name="item.raw.name" />
|
||||||
|
<!-- <svg
|
||||||
class="icon"
|
class="icon"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
font-size="50px"
|
font-size="50px"
|
||||||
|
@ -32,7 +33,7 @@
|
||||||
style="margin: auto"
|
style="margin: auto"
|
||||||
>
|
>
|
||||||
<use xlink:href="#icon-ppt"></use>
|
<use xlink:href="#icon-ppt"></use>
|
||||||
</svg>
|
</svg>-->
|
||||||
</div>
|
</div>
|
||||||
<div class="prepare-body-main-item-info">
|
<div class="prepare-body-main-item-info">
|
||||||
<div class="prepare-item-info-title">{{ item.raw.name }}</div>
|
<div class="prepare-item-info-title">{{ item.raw.name }}</div>
|
||||||
|
@ -59,12 +60,14 @@
|
||||||
<script>
|
<script>
|
||||||
import uploaderState from '@/store/modules/uploader'
|
import uploaderState from '@/store/modules/uploader'
|
||||||
import { getToken } from '@/utils/auth'
|
import { getToken } from '@/utils/auth'
|
||||||
import CryptoJS from 'crypto-js'
|
// import CryptoJS from 'crypto-js/md5'
|
||||||
|
import SparkMD5 from 'spark-md5'
|
||||||
import { DeleteFilled } from '@element-plus/icons-vue'
|
import { DeleteFilled } from '@element-plus/icons-vue'
|
||||||
|
import FileImage from '@/components/file-image/index.vue'
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
export default {
|
export default {
|
||||||
name: 'Uploader',
|
name: 'Uploader',
|
||||||
components: { DeleteFilled },
|
components: { DeleteFilled, FileImage },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
timer: null,
|
timer: null,
|
||||||
|
@ -147,13 +150,14 @@ export default {
|
||||||
},
|
},
|
||||||
getFileMD5(file) {
|
getFileMD5(file) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const fileReader = new FileReader()
|
let fileReader = new FileReader()
|
||||||
fileReader.onload = (e) => {
|
let Spark = new SparkMD5.ArrayBuffer()
|
||||||
const buffer = e.target.result
|
fileReader.readAsArrayBuffer(file)
|
||||||
let md5 = CryptoJS.MD5(buffer).toString()
|
fileReader.onload = function (e) {
|
||||||
|
Spark.append(e.target.result)
|
||||||
|
let md5 = Spark.end()
|
||||||
resolve(md5)
|
resolve(md5)
|
||||||
}
|
}
|
||||||
fileReader.readAsArrayBuffer(file)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
removeUploadFile(uid) {
|
removeUploadFile(uid) {
|
||||||
|
|
|
@ -28,6 +28,8 @@ export class CanvasClickEvent {
|
||||||
|
|
||||||
// 事件:按下鼠标
|
// 事件:按下鼠标
|
||||||
canvas?.on('mouse:down', (e) => {
|
canvas?.on('mouse:down', (e) => {
|
||||||
|
console.log(222222222222222222222222222)
|
||||||
|
|
||||||
this.isMouseDown = true
|
this.isMouseDown = true
|
||||||
if (this.isSpaceKeyDown) {
|
if (this.isSpaceKeyDown) {
|
||||||
return
|
return
|
||||||
|
@ -147,6 +149,8 @@ export class CanvasClickEvent {
|
||||||
|
|
||||||
// 事件:移动鼠标
|
// 事件:移动鼠标
|
||||||
canvas?.on('mouse:move', (e) => {
|
canvas?.on('mouse:move', (e) => {
|
||||||
|
console.log(222222222222222222222222222)
|
||||||
|
|
||||||
if (this.isMouseDown) {
|
if (this.isMouseDown) {
|
||||||
// Press space, drag the canvas, stop drawing.
|
// Press space, drag the canvas, stop drawing.
|
||||||
if (this.isSpaceKeyDown) {
|
if (this.isSpaceKeyDown) {
|
||||||
|
@ -179,6 +183,8 @@ export class CanvasClickEvent {
|
||||||
|
|
||||||
// 事件:松开鼠标
|
// 事件:松开鼠标
|
||||||
canvas?.on('mouse:up', (e) => {
|
canvas?.on('mouse:up', (e) => {
|
||||||
|
console.log(222222222222222222222222222)
|
||||||
|
|
||||||
this.isMouseDown = false
|
this.isMouseDown = false
|
||||||
if (this.autoDrawInk?.[0]?.length > 3) {
|
if (this.autoDrawInk?.[0]?.length > 3) {
|
||||||
autoDrawData.addInk([...this.autoDrawInk])
|
autoDrawData.addInk([...this.autoDrawInk])
|
||||||
|
|
|
@ -36,6 +36,7 @@ const useUserStore = defineStore(
|
||||||
getInfo() {
|
getInfo() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
getInfo().then(res => {
|
getInfo().then(res => {
|
||||||
|
res.user.avatar = import.meta.env.VITE_APP_BASE_API + res.user.avatar
|
||||||
const user = res.user
|
const user = res.user
|
||||||
this.user = user
|
this.user = user
|
||||||
const avatar = (user.avatar == "" || user.avatar == null) ? defAva : user.avatar;
|
const avatar = (user.avatar == "" || user.avatar == null) ? defAva : user.avatar;
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
|
||||||
|
import array from 'lodash/array'
|
||||||
|
export const hasPermission = (value, def = true) => {
|
||||||
|
// 不传值,默认视为有权限,不做鉴权
|
||||||
|
if (!value) {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
|
const allCodeList = useUserStore().roles
|
||||||
|
// 如果不是数组,直接判断pinia里的权限数组有没有相同的元素即可
|
||||||
|
if (!Array.isArray(value)) {
|
||||||
|
return allCodeList.includes(value)
|
||||||
|
}
|
||||||
|
// intersection是lodash提供的一个方法,用于返回一个所有给定数组都存在的元素组成的数组
|
||||||
|
return array.intersection(value, allCodeList).length > 0
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const baseConfig = {
|
||||||
|
// Electron 设置cookie
|
||||||
|
url: 'https://file.ysaix.com:7868',
|
||||||
|
//cookie 名称 这里为 token
|
||||||
|
name: 'Admin-Token',
|
||||||
|
//cookie 值
|
||||||
|
value: userStore.token,
|
||||||
|
// 域名
|
||||||
|
domain: 'file.ysaix.com',
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 作业
|
||||||
|
const homeWork = {
|
||||||
|
data: { ...baseConfig},
|
||||||
|
// 完整路径
|
||||||
|
fullPath: `${baseConfig.url}/teaching/classtaskassign?titleName=%E4%BD%9C%E4%B8%9A%E5%B8%83%E7%BD%AE`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 高考研读
|
||||||
|
const gk = {
|
||||||
|
data: { ...baseConfig},
|
||||||
|
fullPath: `${baseConfig.url}/education/colentrance`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 课标研读
|
||||||
|
const standard = {
|
||||||
|
data: { ...baseConfig},
|
||||||
|
fullPath: `${baseConfig.url}/teaching/chatwithstandard`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 教学大模型
|
||||||
|
const aiModel = {
|
||||||
|
data: { ...baseConfig},
|
||||||
|
fullPath: `${baseConfig.url}/platofai`
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
homeWork,
|
||||||
|
gk,
|
||||||
|
standard,
|
||||||
|
aiModel
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
// 所有事件
|
||||||
|
export function handleevent(canvas, imgarr, type = 'defalut') {
|
||||||
|
// 鼠标按下
|
||||||
|
canvas.on('mouse:down', function (e) {})
|
||||||
|
// // 监听鼠标移动事件
|
||||||
|
// canvas.on('mouse:move', (options) => {
|
||||||
|
// console.log('Mouse move event:', options);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// 监听鼠标释放事件
|
||||||
|
canvas.on('mouse:up', (options) => {
|
||||||
|
//判断是点击的哪一个
|
||||||
|
if (type == 'defalut') {
|
||||||
|
if (imgarr.value[0].index == 0) {
|
||||||
|
imgarr.value[0].JSONdata = canvas.toJSON()
|
||||||
|
}
|
||||||
|
if (imgarr.value[1].index == 0) {
|
||||||
|
imgarr.value[1].JSONdata = canvas.toJSON()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (imgarr.value[0].index == 1) {
|
||||||
|
imgarr.value[0].JSONdata = canvas.toJSON()
|
||||||
|
}
|
||||||
|
if (imgarr.value[1].index == 1) {
|
||||||
|
imgarr.value[1].JSONdata = canvas.toJSON()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 保存数据
|
||||||
|
export function savecanvsStore(imgarr, canvsStore) {
|
||||||
|
canvsStore.pageArr = mergeAndReplace(canvsStore.pageArr, imgarr.value)
|
||||||
|
// console.log(canvsStore.pageArr,22222222222222222222+'存入')
|
||||||
|
}
|
||||||
|
// 重显数据
|
||||||
|
export function displayData(canvas, canvsStore, canvasobj, fabric, img) {
|
||||||
|
// 初始化
|
||||||
|
if (!canvsStore.pageArr.length) {
|
||||||
|
fabric.Image.fromURL(img.src, (img) => {
|
||||||
|
img.set({
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
scaleX: canvas.value.width / img.width,
|
||||||
|
scaleY: canvas.value.height / img.height
|
||||||
|
})
|
||||||
|
canvas.value.setBackgroundImage(img, canvas.value.renderAll.bind(canvas.value))
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
canvsStore.pageArr.forEach((item) => {
|
||||||
|
//初始化
|
||||||
|
if (item.page == canvasobj.page) {
|
||||||
|
canvas.value.clear() // 清除 Canvas
|
||||||
|
// console.log(item.JSONdata, '找到一样的数据')
|
||||||
|
canvas.value.loadFromJSON(item.JSONdata, () => {
|
||||||
|
// 在所有对象加载完成后重新渲染画布
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
// 渲染所有对象
|
||||||
|
canvas.value.renderAll.bind(canvas.value)
|
||||||
|
canvas.value.renderAll()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘
|
||||||
|
canvas.value.clear() // 清除 Canvas
|
||||||
|
requestAnimationFrame(function () {
|
||||||
|
fabric.Image.fromURL(img.src, (img) => {
|
||||||
|
img.set({
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
scaleX: canvas.value.width / img.width,
|
||||||
|
scaleY: canvas.value.height / img.height
|
||||||
|
})
|
||||||
|
canvas.value.setBackgroundImage(img, canvas.value.renderAll.bind(canvas.value))
|
||||||
|
})
|
||||||
|
// 渲染所有对象
|
||||||
|
canvas.value.renderAll.bind(canvas.value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//page 一样替换
|
||||||
|
const mergeAndReplace = (arr1, arr2) => {
|
||||||
|
// // 用于存储替换后的数组
|
||||||
|
// const resultArray = array1.map(item1 => {
|
||||||
|
// // 在 array2 中查找 page 相同的对象
|
||||||
|
// const replacement = array2.find(item2 => item2.page == item1.page);
|
||||||
|
// // 如果找到替换对象,则返回替换对象,否则返回原对象
|
||||||
|
// return replacement ? replacement : item1;
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // 将 array2 中 page 不在 array1 中的对象追加到结果数组中
|
||||||
|
// array2.forEach(item2 => {
|
||||||
|
// const existsInArray1 = array1.some(item1 => item1.page == item2.page);
|
||||||
|
// if (!existsInArray1) {
|
||||||
|
// resultArray.push(item2);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return resultArray;
|
||||||
|
|
||||||
|
// 创建一个映射,将 arr2 中的对象按 page 属性存储
|
||||||
|
let map = new Map(arr2.map((item) => [item.page, item]))
|
||||||
|
|
||||||
|
// 使用 map 替换 arr1 中相应 page 的对象,并添加 arr2 中的对象
|
||||||
|
arr1 = arr1.map((item) => (map.has(item.page) ? map.get(item.page) : item))
|
||||||
|
|
||||||
|
// 将 map 中存在但 arr1 中不存在的对象添加到 arr1
|
||||||
|
for (let [page, obj] of map) {
|
||||||
|
if (!arr1.some((item) => item.page === page)) {
|
||||||
|
arr1.push(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化数据
|
||||||
|
export function initcanvasdata(canvas) {
|
||||||
|
canvas.value.clear() // 清除 Canvas
|
||||||
|
// 设置画布的背景色或其他属性
|
||||||
|
canvas.value.backgroundColor = 'rgba(255, 255, 255, 1)' // 白色背景
|
||||||
|
|
||||||
|
// 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘
|
||||||
|
requestAnimationFrame(function () {
|
||||||
|
// 渲染所有对象
|
||||||
|
canvas.value.renderAll.bind(canvas.value)
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,5 +1,49 @@
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
|
||||||
|
export const asyncLocalFile = (item) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
//判断是否需要从线上拿新的文件
|
||||||
|
isAsyncLocalFile(item.fileNewName, item.lastModifyTime, item.fileMd5).then(
|
||||||
|
({ isAsync, type }) => {
|
||||||
|
item.async = !isAsync
|
||||||
|
if (isAsync === true) {
|
||||||
|
item.async = 'on'
|
||||||
|
if (type === 'down') {
|
||||||
|
ipcRenderer.send('download-file-default', {
|
||||||
|
url: item.fileFullPath,
|
||||||
|
fileName: item.fileNewName
|
||||||
|
})
|
||||||
|
ipcRenderer.once('download-file-default' + item.fileNewName, (e, isSuccess) => {
|
||||||
|
item.async = isSuccess
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (type === 'upload') {
|
||||||
|
let cookie = localStorage.getItem('Admin-Token')
|
||||||
|
ipcRenderer.send('upload-file-change', {
|
||||||
|
id: item.id,
|
||||||
|
fileNewName: item.fileNewName,
|
||||||
|
cookie,
|
||||||
|
fileType: item.fileType
|
||||||
|
})
|
||||||
|
ipcRenderer.once(
|
||||||
|
'upload-file-change-success' + item.fileNewName,
|
||||||
|
(e, { data, md5 }) => {
|
||||||
|
item.fileSize = data.fileSize
|
||||||
|
item.md5 = md5
|
||||||
|
item.async = true
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const isHaveLocalFile = async (fileNewName) => {
|
export const isHaveLocalFile = async (fileNewName) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
ipcRenderer.send('is-have-local-file', fileNewName)
|
ipcRenderer.send('is-have-local-file', fileNewName)
|
||||||
|
@ -9,6 +53,15 @@ export const isHaveLocalFile = async (fileNewName) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const isAsyncLocalFile = async (fileNewName, lastModifyTime, md5) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
ipcRenderer.send('is-async-local-file', { fileNewName, lastModifyTime, md5 })
|
||||||
|
ipcRenderer.once('is-async-local-file-reply' + fileNewName, (e, { isAsync, type }) => {
|
||||||
|
resolve({ isAsync, type })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const parseCataByNode = (node) => {
|
export const parseCataByNode = (node) => {
|
||||||
if (node.parentNode) {
|
if (node.parentNode) {
|
||||||
let arr = parseCataByNode(node.parentNode)
|
let arr = parseCataByNode(node.parentNode)
|
||||||
|
@ -31,9 +84,12 @@ export const exportFile = async (list) => {
|
||||||
export const creatPPT = (name, uploadData) => {
|
export const creatPPT = (name, uploadData) => {
|
||||||
JSON.parse(JSON.stringify(uploadData))
|
JSON.parse(JSON.stringify(uploadData))
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let cookie = localStorage.getItem('Admin-Token');
|
let cookie = localStorage.getItem('Admin-Token')
|
||||||
console.log(cookie)
|
ipcRenderer.send('creat-file-default', {
|
||||||
ipcRenderer.send('creat-file-default', { name, uploadData:JSON.parse(JSON.stringify(uploadData)), cookie })
|
name,
|
||||||
|
uploadData: JSON.parse(JSON.stringify(uploadData)),
|
||||||
|
cookie
|
||||||
|
})
|
||||||
ipcRenderer.once('creat-file-default-reply', (e, res) => {
|
ipcRenderer.once('creat-file-default-reply', (e, res) => {
|
||||||
resolve(res)
|
resolve(res)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,17 +1,28 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="pdfbox" ref="pdfbox">
|
<div class="pdfbox" ref="pdfbox">
|
||||||
<pdfCanvas :pdfObj="pdfObj" ref="pdfCanvaslist" @update:numPages="handleUpdate" />
|
<pdfCanvas :pdfObj="pdfObj" ref="pdfCanvaslist" @update:numPagesTotal="handleUpdate" />
|
||||||
<div class="pdf-btn">
|
<div class="pdf-btn">
|
||||||
<el-button style=" border-top-left-radius: 8px;" @click="switchPageMode">
|
<el-button
|
||||||
|
style="border-top-left-radius: 8px"
|
||||||
|
@click="switchPageMode"
|
||||||
|
:disabled="numPagesTotal == 1"
|
||||||
|
>
|
||||||
<i class="iconfont icon-danyemoban" v-if="pdfObj.numberOfPdf == 2"></i>
|
<i class="iconfont icon-danyemoban" v-if="pdfObj.numberOfPdf == 2"></i>
|
||||||
<i class="iconfont icon-shuangye" v-if="pdfObj.numberOfPdf == 1"></i>
|
<i class="iconfont icon-shuangye" v-if="pdfObj.numberOfPdf == 1"></i>
|
||||||
<span class="texts">{{ pdfObj.numberOfPdf == 1 ? '双页' : '单页' }}</span>
|
<span class="texts">{{ pdfObj.numberOfPdf == 1 ? '双页' : '单页' }}</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="navtopage('up')" :disabled="pdfObj.numPages==1">
|
<el-button @click="navtopage('up')" :disabled="pdfObj.numPages == 1 || numPagesTotal == 1">
|
||||||
<i class="iconfont icon-shangyiye"></i>
|
<i class="iconfont icon-shangyiye"></i>
|
||||||
<span class="texts">上一页</span>
|
<span class="texts">上一页</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="navtopage('lower')" :disabled="pdfObj.numPages >= numPages/pdfObj.numberOfPdf" >
|
<el-button
|
||||||
|
@click="navtopage('lower')"
|
||||||
|
:disabled="
|
||||||
|
pdfObj.numberOfPdf == 1
|
||||||
|
? pdfObj.numPages >= numPagesTotal
|
||||||
|
: pdfObj.numPages >= numPagesTotal - 1 || numPagesTotal == 1
|
||||||
|
"
|
||||||
|
>
|
||||||
<i class="iconfont icon-xiayiye"></i>
|
<i class="iconfont icon-xiayiye"></i>
|
||||||
<span class="texts">下一页</span>
|
<span class="texts">下一页</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
@ -20,59 +31,59 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch, reactive } from 'vue';
|
import { ref, onMounted, watch, reactive } from 'vue'
|
||||||
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf';
|
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf'
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc = '/lib/build/pdf.worker.mjs';
|
pdfjsLib.GlobalWorkerOptions.workerSrc = '/lib/build/pdf.worker.mjs'
|
||||||
import pdfCanvas from '@/components/pdf/index.vue';
|
import pdfCanvas from '@/components/pdf/index.vue'
|
||||||
|
|
||||||
// 传过去的参数
|
// 传过去的参数
|
||||||
const pdfObj = reactive({
|
const pdfObj = reactive({
|
||||||
numberOfPdf: 2, //显示几页
|
numberOfPdf: 2, //显示几页
|
||||||
pdfUrl: '/aaa.pdf', //url
|
pdfUrl: '/aaa.pdf', //url
|
||||||
numPages: 1 //当前页数
|
numPages: 1 //当前页数
|
||||||
});
|
})
|
||||||
const numPages=ref(0)
|
// 总条数
|
||||||
|
const numPagesTotal = ref(0)
|
||||||
const pdfCanvaslist=ref(null);
|
const pdfCanvaslist = ref(null)
|
||||||
const navtopage = (type) => {
|
const navtopage = (type) => {
|
||||||
const maxpage=numPages.value/pdfObj.numberOfPdf
|
let num = 1
|
||||||
if(type=='up'){
|
if (pdfObj.numberOfPdf == 2) {
|
||||||
pdfObj.numPages--;
|
num = 2
|
||||||
}else{
|
|
||||||
pdfObj.numPages++;
|
|
||||||
}
|
}
|
||||||
if(pdfObj.numPages>maxpage) return
|
if (type == 'up') {
|
||||||
|
pdfObj.numPages -= num
|
||||||
|
} else {
|
||||||
|
pdfObj.numPages += num
|
||||||
|
}
|
||||||
|
if (pdfObj.numPages > numPagesTotal.value) return
|
||||||
pdfCanvaslist.value.initPdf()
|
pdfCanvaslist.value.initPdf()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleUpdate = (data) => {
|
const handleUpdate = (data) => {
|
||||||
numPages.value=data
|
numPagesTotal.value = data
|
||||||
|
if (numPagesTotal.value == 1) {
|
||||||
|
pdfObj.numberOfPdf = 1
|
||||||
|
pdfCanvaslist.value.initPdf('restone')
|
||||||
}
|
}
|
||||||
const divideWithRemainder=(num1, num2)=> {
|
|
||||||
// 执行除法运算
|
|
||||||
const quotient = Math.floor(num1 / num2);
|
|
||||||
const remainder = num1 % num2;
|
|
||||||
|
|
||||||
// 如果有余数,则结果加 1
|
|
||||||
return remainder === 0 ? quotient : quotient + 1;
|
|
||||||
}
|
}
|
||||||
// 单双页切换
|
// 单双页切换
|
||||||
const switchPageMode = () => {
|
const switchPageMode = () => {
|
||||||
// 单页切多页
|
// 单页切多页
|
||||||
if (pdfObj.numberOfPdf == 1) {
|
if (pdfObj.numberOfPdf == 1) {
|
||||||
pdfObj.numberOfPdf=2;
|
// 如果最后一页 切双页需要减1
|
||||||
pdfObj.numPages= divideWithRemainder(pdfObj.numPages,pdfObj.numberOfPdf)
|
if (pdfObj.numPages == numPagesTotal.value) {
|
||||||
|
pdfObj.numPages = pdfObj.numPages - 1
|
||||||
|
}
|
||||||
|
pdfObj.numberOfPdf = 2
|
||||||
|
// 初始化第二个pdf canvas
|
||||||
|
pdfCanvaslist.value.initPdfone()
|
||||||
} else {
|
} else {
|
||||||
// 多页切单页
|
// 多页切单页
|
||||||
pdfObj.numberOfPdf=1;
|
pdfObj.numberOfPdf = 1
|
||||||
pdfObj.numPages=pdfObj.numPages*2-1
|
pdfCanvaslist.value.initPdf('restone')
|
||||||
}
|
}
|
||||||
|
|
||||||
pdfCanvaslist.value.initPdf()
|
|
||||||
}
|
}
|
||||||
onMounted(async () => {
|
onMounted(async () => {})
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--选择学科-->
|
<!--选择学科-->
|
||||||
<SelectSubject v-model="isSubject" v-if="isSubject" class="select-subject" @onSuccess="successEditSubject" />
|
<SelectSubject v-model="isSubject" @onSuccess="successEditSubject" />
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, reactive, ref } from 'vue'
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
|
@ -202,7 +202,5 @@ onMounted(()=>{
|
||||||
.el-form-item {
|
.el-form-item {
|
||||||
margin-bottom: 40px;
|
margin-bottom: 40px;
|
||||||
}
|
}
|
||||||
.select-subject{
|
|
||||||
-webkit-app-region: drag;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -100,10 +100,10 @@ import { Check, UploadFilled, Switch } from '@element-plus/icons-vue'
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
import FileImage from '@/components/file-image/index.vue'
|
import FileImage from '@/components/file-image/index.vue'
|
||||||
import { isHaveLocalFile } from '@/utils/talkFile'
|
import { asyncLocalFile } from '@/utils/talkFile'
|
||||||
import { toTimeText } from '@/utils/date'
|
import { toTimeText } from '@/utils/date'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { deleteSmarttalk, updateSmarttalk } from '@/api/file'
|
import { deleteSmarttalk, updateSmarttalk, getPrepareById } from '@/api/file'
|
||||||
|
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
export default {
|
export default {
|
||||||
|
@ -124,6 +124,11 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: { 'on-move': null, 'on-delete': null },
|
emits: { 'on-move': null, 'on-delete': null },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
listenList: []
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
editTalk(item) {
|
editTalk(item) {
|
||||||
ElMessageBox.prompt('请输入新的名称', '重命名', {
|
ElMessageBox.prompt('请输入新的名称', '重命名', {
|
||||||
|
@ -142,8 +147,7 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {})
|
||||||
})
|
|
||||||
},
|
},
|
||||||
downloadFile(item) {
|
downloadFile(item) {
|
||||||
ipcRenderer.send('save-as', item.fileFullPath, item.fileShowName)
|
ipcRenderer.send('save-as', item.fileFullPath, item.fileShowName)
|
||||||
|
@ -156,7 +160,6 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
closePopver(index) {
|
closePopver(index) {
|
||||||
console.log(this.$refs['popover_' + index])
|
|
||||||
this.$refs['popover_' + index].hide()
|
this.$refs['popover_' + index].hide()
|
||||||
},
|
},
|
||||||
moveSmarttalkFun(item) {
|
moveSmarttalkFun(item) {
|
||||||
|
@ -179,21 +182,32 @@ export default {
|
||||||
return temp + 'GB'
|
return temp + 'GB'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openFileWin(item) {
|
openFileWin(items) {
|
||||||
isHaveLocalFile(item.fileNewName).then((res) => {
|
getPrepareById(items.id).then((item) => {
|
||||||
if (res === true) {
|
Object.assign(items, item)
|
||||||
|
asyncLocalFile(items).then(() => {
|
||||||
ipcRenderer.send('open-path-app', item.fileNewName)
|
ipcRenderer.send('open-path-app', item.fileNewName)
|
||||||
} else {
|
if (this.listenList.indexOf(item.fileNewName) === -1) {
|
||||||
item.async = 'on'
|
this.listenList.push(item.fileNewName)
|
||||||
ipcRenderer.once('download-file-default' + item.fileNewName, (e, isSuccess) => {
|
let cookie = localStorage.getItem('Admin-Token')
|
||||||
item.async = isSuccess
|
ipcRenderer.send('listen-file-change', {
|
||||||
|
id: item.id,
|
||||||
|
fileNewName: item.fileNewName,
|
||||||
|
md5: item.fileMd5,
|
||||||
|
cookie,
|
||||||
|
fileType: item.fileType
|
||||||
})
|
})
|
||||||
ipcRenderer.send('download-file-default', {
|
ipcRenderer.on('listen-file-change-on' + item.fileNewName, () => {
|
||||||
url: item.fileFullPath,
|
item.async = 'on'
|
||||||
fileName: item.fileNewName
|
})
|
||||||
|
ipcRenderer.on('listen-file-change-success' + item.fileNewName, (e, { data, md5 }) => {
|
||||||
|
item.fileSize = data.fileSize
|
||||||
|
item.md5 = md5
|
||||||
|
item.async = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,27 @@
|
||||||
<div v-loading="isLoading" class="page-resource flex">
|
<div v-loading="isLoading" class="page-resource flex">
|
||||||
<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="textbook-img">
|
||||||
|
<el-image style="width: 80px; height: 110px" :src="curBookImg" />
|
||||||
|
</div>
|
||||||
|
<div class="top-item">
|
||||||
|
<el-button class="btn" @click="handleOutLink('standard')">课标研读</el-button>
|
||||||
|
<el-button class="btn" >电子课本</el-button>
|
||||||
|
<el-button class="btn" @click="handleOutLink('gk')">高考研读</el-button>
|
||||||
|
<el-button class="btn" @click="handleOutLink('aiModel')">教学大模型</el-button>
|
||||||
|
</div>
|
||||||
|
<el-button type="primary" class="to-class-btn">
|
||||||
|
<i class="iconfont icon-lingdang"></i>上课</el-button>
|
||||||
|
</div>
|
||||||
<div class="prepare-body-header">
|
<div class="prepare-body-header">
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label style="font-size: 15px">共{{ currentFileList.length }}个文件</label>
|
<label style="font-size: 15px">共{{ currentFileList.length }}个文件</label>
|
||||||
<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>
|
||||||
|
@ -29,38 +37,22 @@
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex">
|
<div style="display: flex">
|
||||||
|
<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">
|
||||||
>
|
|
||||||
<file-list-item
|
|
||||||
v-for="(item, index) in currentFileList"
|
|
||||||
:key="index"
|
|
||||||
:item="item"
|
|
||||||
:index="index"
|
|
||||||
@on-move="onMoveSingleFile"
|
|
||||||
@on-delete="deleteTalk"
|
|
||||||
>
|
|
||||||
<el-checkbox label="" :value="item" />
|
<el-checkbox label="" :value="item" />
|
||||||
</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" />
|
||||||
|
@ -79,9 +71,12 @@ import FileListItem from '@/views/prepare/container/file-list-item.vue'
|
||||||
import { getSmarttalkPage, moveSmarttalk } from '@/api/file'
|
import { getSmarttalkPage, moveSmarttalk } from '@/api/file'
|
||||||
import { toTimeText } from '@/utils/date'
|
import { toTimeText } from '@/utils/date'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { isHaveLocalFile, parseCataByNode, creatPPT } from '@/utils/talkFile'
|
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 outLink from '@/utils/linkConfig'
|
||||||
|
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Prepare',
|
name: 'Prepare',
|
||||||
components: { ChooseTextbook, Refresh, uploadDialog, FileListItem, FileOperBatch, MoveFile },
|
components: { ChooseTextbook, Refresh, uploadDialog, FileListItem, FileOperBatch, MoveFile },
|
||||||
|
@ -104,7 +99,9 @@ export default {
|
||||||
levelSecondId: null,
|
levelSecondId: null,
|
||||||
fileSource: '个人',
|
fileSource: '个人',
|
||||||
fileRoot: '备课'
|
fileRoot: '备课'
|
||||||
}
|
},
|
||||||
|
// 当前教材封面图
|
||||||
|
curBookImg: '',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -120,21 +117,13 @@ export default {
|
||||||
this.callback(param)
|
this.callback(param)
|
||||||
})
|
})
|
||||||
this.lastAsyncAllTime = localStorage.getItem('lastAsyncAllTime')
|
this.lastAsyncAllTime = localStorage.getItem('lastAsyncAllTime')
|
||||||
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
// const destination = '0901高一【数学(人教A版)】集合的概念-PPT课件.pptx'
|
|
||||||
// ipcRenderer.send('open-path-app',this.filePath)
|
|
||||||
// const source = 'D:\\edufile\\0901高一【数学(人教A版)】集合的概念-PPT课件.pptx'
|
|
||||||
// ipcRenderer.send('copy-file-default',{ source, destination })
|
|
||||||
// ipcRenderer.send('download-file-default',this.fileUrl)
|
|
||||||
// getSmarttalkPage({nowPage:1,pageSize:2}).then(res=>{
|
|
||||||
// console.log(res)
|
|
||||||
// })
|
|
||||||
// let filePath = window.rootTalkFilePath + item.fileNewName
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
createFile() {
|
createFile() {
|
||||||
creatPPT('新建ppt文档.pptx',this.uploadData).then((res) => {
|
creatPPT(this.currentNode.label + '.pptx', this.uploadData).then((res) => {
|
||||||
this.currentFileList.unshift(res.resData)
|
this.currentFileList.unshift(res.resData)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -160,35 +149,6 @@ export default {
|
||||||
clickChoose(value) {
|
clickChoose(value) {
|
||||||
this.checkFileList = value ? this.currentFileList : []
|
this.checkFileList = value ? this.currentFileList : []
|
||||||
},
|
},
|
||||||
async asyncAllFile() {
|
|
||||||
this.lastAsyncAllTime = new Date()
|
|
||||||
localStorage.setItem('lastAsyncAllTime', this.lastAsyncAllTime)
|
|
||||||
this.asyncAllFileVisiable = true
|
|
||||||
const test = (item) => {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
isHaveLocalFile(item.fileNewName).then((res) => {
|
|
||||||
item.async = res
|
|
||||||
if (res === false) {
|
|
||||||
ipcRenderer.send('download-file-default', {
|
|
||||||
url: item.fileFullPath,
|
|
||||||
fileName: item.fileNewName
|
|
||||||
})
|
|
||||||
item.async = 'on'
|
|
||||||
ipcRenderer.once('download-file-default' + item.fileNewName, (e, isSuccess) => {
|
|
||||||
item.async = isSuccess
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
for (let i = 0; i < this.currentFileList.length; i++) {
|
|
||||||
await test(this.currentFileList[i])
|
|
||||||
}
|
|
||||||
this.asyncAllFileVisiable = false
|
|
||||||
},
|
|
||||||
deleteTalk(item) {
|
deleteTalk(item) {
|
||||||
let index = this.currentFileList.indexOf(item)
|
let index = this.currentFileList.indexOf(item)
|
||||||
this.currentFileList.splice(index, 1)
|
this.currentFileList.splice(index, 1)
|
||||||
|
@ -254,15 +214,7 @@ export default {
|
||||||
}
|
}
|
||||||
console.log('File copied to:', filePath)
|
console.log('File copied to:', filePath)
|
||||||
},
|
},
|
||||||
nodeClick(data) {
|
asyncAllFile() {
|
||||||
if (this.currentNode.id === data.node.id) return
|
|
||||||
this.checkFileList = []
|
|
||||||
let cata = parseCataByNode(data.node)
|
|
||||||
this.currentNode = data.node
|
|
||||||
this.uploadData.levelFirstId = cata[0]
|
|
||||||
this.uploadData.levelSecondId = cata[1]
|
|
||||||
this.uploadData.levelThirdId = cata[2]
|
|
||||||
this.uploadData.textbookId = data.textBook.curBookId
|
|
||||||
this.isLoading = true
|
this.isLoading = true
|
||||||
getSmarttalkPage({
|
getSmarttalkPage({
|
||||||
...this.uploadData,
|
...this.uploadData,
|
||||||
|
@ -270,20 +222,44 @@ export default {
|
||||||
isAsc: 'desc',
|
isAsc: 'desc',
|
||||||
pageSize: 500
|
pageSize: 500
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then(async (res) => {
|
||||||
this.currentFileList = [...res.rows]
|
this.currentFileList = [...res.rows]
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
this.currentFileList.filter((item) => {
|
this.lastAsyncAllTime = new Date()
|
||||||
isHaveLocalFile(item.fileNewName).then((res) => {
|
localStorage.setItem('lastAsyncAllTime', this.lastAsyncAllTime)
|
||||||
item.async = res
|
this.asyncAllFileVisiable = true
|
||||||
|
for (let i = 0; i < this.currentFileList.length; i++) {
|
||||||
|
let item = this.currentFileList[i]
|
||||||
|
await asyncLocalFile(item)
|
||||||
|
}
|
||||||
|
this.asyncAllFileVisiable = false
|
||||||
})
|
})
|
||||||
})
|
.catch(() => {
|
||||||
})
|
|
||||||
.catch((res) => {
|
|
||||||
console.log(res)
|
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
|
nodeClick(data) {
|
||||||
|
if (this.currentNode.id === data.node.id) return
|
||||||
|
this.curBookImg = data.textBook.curBookImg
|
||||||
|
this.checkFileList = []
|
||||||
|
let cata = parseCataByNode(data.node)
|
||||||
|
this.currentNode = data.node
|
||||||
|
this.uploadData.levelFirstId = cata[0]
|
||||||
|
this.uploadData.levelSecondId = cata[1]
|
||||||
|
this.uploadData.levelThirdId = cata[2]
|
||||||
|
this.uploadData.textbookId = data.textBook.curBookId
|
||||||
|
this.asyncAllFile()
|
||||||
|
},
|
||||||
|
// 打开外部链接
|
||||||
|
handleOutLink(key){
|
||||||
|
// key 对应的 linkConfig.js 外部链接配置
|
||||||
|
let configObj = outLink[key]
|
||||||
|
// 通知主进程
|
||||||
|
ipcRenderer.send('openWindow', {
|
||||||
|
fullPath: configObj.fullPath,
|
||||||
|
cookieData: {...(configObj.data)}
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -321,6 +297,7 @@ export default {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.page-right {
|
.page-right {
|
||||||
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
@ -332,6 +309,55 @@ export default {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
.header-top {
|
||||||
|
height: 150px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: linear-gradient(#97c4ed, #7aa8e5);
|
||||||
|
padding-right: 20px;
|
||||||
|
.textbook-img{
|
||||||
|
height: 120px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
.top-item{
|
||||||
|
width: 230px;
|
||||||
|
|
||||||
|
flex-wrap: wrap;
|
||||||
|
.btn{
|
||||||
|
width: 102px;
|
||||||
|
background: none;
|
||||||
|
color: #ffffff;
|
||||||
|
border-width: 2px;
|
||||||
|
border-color: #ffffff;
|
||||||
|
&:hover{
|
||||||
|
background: rgba(255, 255, 255, 0.3)
|
||||||
|
}
|
||||||
|
&:first-child{
|
||||||
|
margin-left: 12px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
&:nth-child(2){
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.to-class-btn{
|
||||||
|
width: 130px;
|
||||||
|
height: 80px;
|
||||||
|
margin-left: 25px;
|
||||||
|
font-size: 18px;
|
||||||
|
.icon-lingdang{
|
||||||
|
margin-right: 5px;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.prepare-body-header {
|
.prepare-body-header {
|
||||||
height: 60px;
|
height: 60px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -340,6 +366,7 @@ export default {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.prepare-body-main {
|
.prepare-body-main {
|
||||||
|
|
|
@ -99,6 +99,7 @@ const state = reactive({
|
||||||
|
|
||||||
function getUser() {
|
function getUser() {
|
||||||
getUserProfile().then((response) => {
|
getUserProfile().then((response) => {
|
||||||
|
response.data.avatar = import.meta.env.VITE_APP_BASE_API + response.data.avatar
|
||||||
state.user = response.data
|
state.user = response.data
|
||||||
state.roleGroup = response.roleGroup
|
state.roleGroup = response.roleGroup
|
||||||
state.postGroup = response.postGroup
|
state.postGroup = response.postGroup
|
||||||
|
|
|
@ -84,7 +84,7 @@ const title = ref('修改头像')
|
||||||
|
|
||||||
//图片裁剪数据
|
//图片裁剪数据
|
||||||
const options = reactive({
|
const options = reactive({
|
||||||
img: userStore.avatar, // 裁剪图片的地址
|
img: userStore.user.avatar, // 裁剪图片的地址
|
||||||
autoCrop: true, // 是否默认生成截图框
|
autoCrop: true, // 是否默认生成截图框
|
||||||
autoCropWidth: 200, // 默认生成截图框宽度
|
autoCropWidth: 200, // 默认生成截图框宽度
|
||||||
autoCropHeight: 200, // 默认生成截图框高度
|
autoCropHeight: 200, // 默认生成截图框高度
|
||||||
|
@ -155,7 +155,7 @@ function uploadImg() {
|
||||||
uploadAvatar(formData).then((response) => {
|
uploadAvatar(formData).then((response) => {
|
||||||
open.value = false
|
open.value = false
|
||||||
options.img = import.meta.env.VITE_APP_BASE_API + response.imgUrl
|
options.img = import.meta.env.VITE_APP_BASE_API + response.imgUrl
|
||||||
userStore.avatar = options.img
|
userStore.user.avatar = options.img
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: '上传成功',
|
message: '上传成功',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
}}</el-button>
|
}}</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" class="search-box flex">
|
<el-col :span="12" class="search-box flex">
|
||||||
<el-input v-model="sourceStore.query.fileName" @input="sourceStore.changeName" style="width: 240px" placeholder="请输入关键词" />
|
<el-input v-model="sourceStore.query.fileName" @input="sourceStore.changeName" style="width: 240px"
|
||||||
|
placeholder="请输入关键词" />
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row class="resoure-btns">
|
<el-row class="resoure-btns">
|
||||||
|
@ -58,6 +59,7 @@ const sourceStore = useResoureStore()
|
||||||
|
|
||||||
.query-row {
|
.query-row {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
.row-left {
|
.row-left {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
@ -74,6 +76,7 @@ const sourceStore = useResoureStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-button.is-round {
|
.el-button.is-round {
|
||||||
padding: 3px 15px;
|
padding: 3px 15px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<div class="page-right">
|
<div class="page-right">
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<ResoureSearch #add>
|
<ResoureSearch #add>
|
||||||
<el-button type="primary" round @click="openDialog" class="create-btn">
|
<el-button v-if="sourceStore.isCreate" type="primary" round @click="openDialog" class="create-btn">
|
||||||
<i class="iconfont icon-jiahao"></i>
|
<i class="iconfont icon-jiahao"></i>
|
||||||
新建资源</el-button>
|
新建资源</el-button>
|
||||||
</ResoureSearch>
|
</ResoureSearch>
|
||||||
|
@ -28,7 +28,8 @@ 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 { hasPermission } from '@/utils/hasPermission'
|
||||||
|
//
|
||||||
const sourceStore = useResoureStore()
|
const sourceStore = useResoureStore()
|
||||||
const isDialogOpen = ref(false)
|
const isDialogOpen = ref(false)
|
||||||
|
|
||||||
|
@ -74,24 +75,27 @@ const submitFile = (data) => {
|
||||||
let fileList = toRaw(data)
|
let fileList = toRaw(data)
|
||||||
const { textbookId, levelFirstId, levelSecondId, fileSource, fileRoot } = sourceStore.query
|
const { textbookId, levelFirstId, levelSecondId, fileSource, fileRoot } = sourceStore.query
|
||||||
// 给每个文件添加属性
|
// 给每个文件添加属性
|
||||||
let fileData = { textbookId, levelFirstId, levelSecondId, fileSource, fileRoot }
|
|
||||||
fileList.forEach(item => {
|
fileList.forEach(item => {
|
||||||
|
let fileData = { textbookId, levelFirstId, levelSecondId, fileSource, fileRoot }
|
||||||
fileData.fileShowName = item.fileData.fileShowName
|
fileData.fileShowName = item.fileData.fileShowName
|
||||||
fileData.fileFlag = item.fileData.fileFlag
|
fileData.fileFlag = item.fileData.fileFlag
|
||||||
item.fileData = fileData
|
item.fileData = fileData
|
||||||
item.callback = fileCallBack
|
item.callback = fileCallBack
|
||||||
})
|
})
|
||||||
// console.log(fileList)
|
|
||||||
uploaderState().pushFile(fileList)
|
uploaderState().pushFile(fileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const fileCallBack = (res) => {
|
const fileCallBack = (res) => {
|
||||||
console.log(res)
|
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
sourceStore.handleQuery()
|
sourceStore.handleQuery()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
sourceStore.getCreate()
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
|
||||||
import { getSmarttalkPage } from '@/api/file/index'
|
import { getSmarttalkPage } from '@/api/file/index'
|
||||||
import { tabs, resourceType, resourceFormat } from '@/utils/resourceDict'
|
import { tabs, resourceType, resourceFormat } from '@/utils/resourceDict'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
|
import { hasPermission } from '@/utils/hasPermission'
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
@ -21,8 +22,8 @@ const resourceFormatList = [
|
||||||
]
|
]
|
||||||
|
|
||||||
// 校本资源为学校ID
|
// 校本资源为学校ID
|
||||||
tabs.forEach(item =>{
|
tabs.forEach((item) => {
|
||||||
if( item.label == "校本资源"){
|
if (item.label == '校本资源') {
|
||||||
item.value = userStore.user.deptId
|
item.value = userStore.user.deptId
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -43,10 +44,12 @@ export default defineStore('resource', {
|
||||||
//节点数据
|
//节点数据
|
||||||
nodeData: {},
|
nodeData: {},
|
||||||
loading: false,
|
loading: false,
|
||||||
|
//
|
||||||
|
isCreate: true,
|
||||||
//查询条件
|
//查询条件
|
||||||
query: {
|
query: {
|
||||||
textbookId: '',
|
textbookId: '',
|
||||||
fileSource: '平台',
|
fileSource: tabs[0].value,
|
||||||
//资源格式 mp3 ppt ...
|
//资源格式 mp3 ppt ...
|
||||||
fileSuffix: -1,
|
fileSuffix: -1,
|
||||||
// 资源类型 课件 素材 教案
|
// 资源类型 课件 素材 教案
|
||||||
|
@ -80,6 +83,7 @@ export default defineStore('resource', {
|
||||||
},
|
},
|
||||||
changeTab(val) {
|
changeTab(val) {
|
||||||
this.query.fileSource = val
|
this.query.fileSource = val
|
||||||
|
this.getCreate()
|
||||||
this.handleQuery()
|
this.handleQuery()
|
||||||
},
|
},
|
||||||
changeType(val) {
|
changeType(val) {
|
||||||
|
@ -92,8 +96,15 @@ export default defineStore('resource', {
|
||||||
},
|
},
|
||||||
// 关键词搜索
|
// 关键词搜索
|
||||||
changeName() {
|
changeName() {
|
||||||
console.log(this.query.fileName)
|
|
||||||
this.handleQuery()
|
this.handleQuery()
|
||||||
},
|
},
|
||||||
|
getCreate(){
|
||||||
|
if(this.query.fileSource == '平台'){
|
||||||
|
this.isCreate = hasPermission(['platformmanager'])
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
this.isCreate = hasPermission(['schoolteacher','headmaster'])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue