diff --git a/dev-app-update.yml b/dev-app-update.yml index 0a21494..0083a29 100644 --- a/dev-app-update.yml +++ b/dev-app-update.yml @@ -1,3 +1,3 @@ provider: generic -url: https://example.com/auto-updates +url: http://localhost:3000/ updaterCacheDirName: electron-app-updater diff --git a/electron-builder-test.yml b/electron-builder-test.yml new file mode 100644 index 0000000..61fba8f --- /dev/null +++ b/electron-builder-test.yml @@ -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/logo.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/ diff --git a/electron-builder.yml b/electron-builder.yml index 52741c5..cb2cf97 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -12,6 +12,7 @@ asarUnpack: - resources/** win: executableName: AIx + icon: resources/logo.ico nsis: oneClick: false allowToChangeInstallationDirectory: true @@ -41,6 +42,6 @@ appImage: npmRebuild: false publish: provider: generic - url: https://example.com/auto-updates + url: https://file.ysaix.com:7868/src/assets/smarttalk/ electronDownload: mirror: https://npmmirror.com/mirrors/electron/ diff --git a/electron.vite.config.mjs b/electron.vite.config.mjs index fcc5633..0a9ec31 100644 --- a/electron.vite.config.mjs +++ b/electron.vite.config.mjs @@ -26,12 +26,7 @@ export default defineConfig({ // target: 'http://192.168.2.52:7863', changeOrigin: true, rewrite: (p) => p.replace(/^\/dev-api/, '') - }, - '/profile': { - target: 'http://192.168.2.52:7863', - ws: true, - changeOrigin: true - }, + } }, }, plugins: [vue(), WindiCSS()], diff --git a/package.json b/package.json index 8f67cc3..6f96a58 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "build": "electron-vite build", "postinstall": "electron-builder install-app-deps", "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:linux": "npm run build && electron-builder --linux" }, @@ -24,6 +25,7 @@ "@vueuse/core": "^10.11.0", "crypto-js": "^4.2.0", "electron-dl-manager": "^3.0.0", + "electron-log": "^5.1.7", "electron-updater": "^6.1.7", "element-plus": "^2.7.6", "fabric": "5.3.0", @@ -33,6 +35,7 @@ "pdfjs-dist": "^4.4.168", "pinia": "^2.1.7", "pinia-plugin-persistedstate": "^3.2.1", + "spark-md5": "^3.0.2", "vue-cropper": "^1.0.3", "vue-router": "^4.4.0" }, diff --git a/resources/logo.ico b/resources/logo.ico new file mode 100644 index 0000000..4c33239 Binary files /dev/null and b/resources/logo.ico differ diff --git a/src/main/file.js b/src/main/file.js index 7580c8f..5637a23 100644 --- a/src/main/file.js +++ b/src/main/file.js @@ -1,16 +1,105 @@ -import CryptoJS from 'crypto-js' - +import SparkMD5 from 'spark-md5' const fs = require('fs') const path = require('path') import { ElectronDownloadManager } from 'electron-dl-manager' import { dialog } from 'electron' import axios from 'axios' 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() export default async function ({ app, shell, BrowserWindow, ipcMain }) { const userDataPath = app.getPath('userData') const appRootFilePath = userDataPath + '\\selfFile\\' 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) => { let filePath = appRootFilePath + fileNewName 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) }) }) + + /* + * 判断是需要同步本地文件 + * */ + 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 ipcMain.on('open-url-browser', (e, url) => { shell.openPath(url) }) + //使用默认应用打开本地文件 ipcMain.on('open-path-app', (e, destination) => { let path = appRootFilePath + destination @@ -40,65 +158,74 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) { }) }) - //复制文件 + //导出文件 ipcMain.on('export-file-default', (e, list) => { exportFile(list, (res) => { e.reply('export-file-default-reply', res) }) }) - function getFileMD5(file) { - 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) + function uploadFileByFS({ url, path, name, cookie, fileType, formData, success, error }) { + fs.readFile(path, (err, data) => { + if (err) { + return console.error(err) } - fileReader.readAsArrayBuffer(file) + // 配置上传的请求 + const config = { + headers: { + 'Content-Type': 'multipart/form-data', // 或者其他适合上传文件的Content-Type + Authorization: 'Bearer ' + cookie + } + } + Spark.append(data) + let md5 = Spark.end() + // 使用axios上传文件 + let file = new File([data], name, { + type: fileType + }) + const stats = fs.statSync(path) + formData.append('file', file) + 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') - // 读取文件 - fs.readFile(path, (err, data) => { - if (err) { - return console.error(err) + let fileType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation' + let formData = new FormData() + for (let key in uploadData) { + if (Object.prototype.hasOwnProperty.call(uploadData, key)) { + // 检查是否是对象自身的属性 + formData.append(key, uploadData[key]) } - // 配置上传的请求 - const config = { - headers: { - 'Content-Type': 'multipart/form-data', // 或者其他适合上传文件的Content-Type - Authorization: 'Bearer ' + cookie - } + } + formData.append('fileFlag', '教案') + uploadFileByFS({ + url: uploadUrl, + path, + name, + cookie, + fileType, + formData, + success: (response) => { + e.reply('creat-file-default-reply', response.data) + console.log('File uploaded successfully:', response.data) + }, + error: (err) => { + console.error('Error uploading file:', err) } - let md5 = CryptoJS.MD5(data).toString() - let formData = new FormData() - // 使用axios上传文件 - let file = new File([data], name, { - type: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' - }) - formData.append('file', file) - formData.append('md5',md5) - - for (let key in uploadData) { - if (uploadData.hasOwnProperty(key)) { // 检查是否是对象自身的属性 - formData.append(key,uploadData[key]) - } - } - formData.append("fileFlag","教案") - axios - .post(uploadUrl, formData, config) - .then((response) => { - e.reply('creat-file-default-reply', response.data) - console.log('File uploaded successfully:', response.data) - }) - .catch((error) => { - console.error('Error uploading file:', error) - }) }) }) }) @@ -191,6 +318,7 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) { }) }) + /*导出文件*/ function exportFile(list, callback) { let win = BrowserWindow.getFocusedWindow() //通过扩展名识别文件类型 @@ -220,10 +348,12 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) { }) } + /*文件是否已经存在*/ function isHaveFile(path) { return fs.existsSync(path) } + /*判断是否已经存在这个名字的文件,如果已经存在则递增导出*/ function filterCopyFile(path, index = 0) { if (isHaveFile(path) === true) { index++ @@ -234,6 +364,7 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) { } } + /*复制文件*/ function copyRelFile(source, destination, callback) { return new Promise((resolve, reject) => { const readStream = fs.createReadStream(source) @@ -256,6 +387,7 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) { }) } + /*复制文件*/ function copyFile(source, destination, callback) { let path = appRootFilePath + destination createFolder('selfFile').then(() => { @@ -276,6 +408,7 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) { }) } + /*创建文件夹*/ function createFolder(folderName) { return new Promise((resolve, reject) => { const folderPath = path.join(userDataPath, folderName) diff --git a/src/main/index.js b/src/main/index.js index 73d3f5d..0fe8aa0 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -4,11 +4,10 @@ import { electronApp, optimizer, is } from '@electron-toolkit/utils' import icon from '../../resources/icon.png?asset' import File from './file' import Tool from './tool' +import updateInit from './update' File({ app, shell, BrowserWindow, ipcMain }) - - - +process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true' let mainWindow, loginWindow //登录窗口 @@ -27,13 +26,21 @@ function createLoginWindow() { nodeIntegration: true } }) - const loginURL = is.dev ? `http://localhost:5173/#/login` : `file://${__dirname}/index.html/login` - loginWindow.loadURL(loginURL) + // handleUpdate(loginWindow,ipcMain) + // 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.show() }) - + loginWindow.on('closed', () => { loginWindow = null }) @@ -44,7 +51,7 @@ function createMainWindow() { width: 1200, height: 700, show: false, - frame: false, + frame: false, // 无边框 autoHideMenuBar: true, ...(process.platform === 'linux' ? { icon } : {}), webPreferences: { @@ -64,53 +71,47 @@ function createMainWindow() { mainWindow.webContents.openDevTools() if (is.dev && process.env['ELECTRON_RENDERER_URL']) { - mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']) + mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'] ) } else { mainWindow.loadFile(join(__dirname, '../renderer/index.html')) } } + // 作业窗口相关-开发中 -let workWindow -function createWork(data) { - if (workWindow) return - workWindow = new BrowserWindow({ +let linkWindow +async function createLinkWin(data) { + if (linkWindow) return + linkWindow = new BrowserWindow({ width: 650, height: 500, show: false, frame: true, - + maximizable: true, autoHideMenuBar: true, ...(process.platform === 'linux' ? { icon } : {}), webPreferences: { sandbox: false, - nodeIntegration: true + nodeIntegration: true, + worldSafeExecuteJavaScript: true, + contextIsolation: true } }) - - workWindow.webContents.session.cookies.set( - { - url: 'https://file.ysaix.com:7868', - name: 'Admin-Token', - 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() + let cookieDetails = { ...data.cookieData } + await linkWindow.webContents.session.cookies.set(cookieDetails).then(()=>{ + console.log('Cookie is successful'); + }).catch( error =>{ + console.error('Cookie is error', error); }) - workWindow.on('closed', () => { - workWindow = null + + linkWindow.loadURL(data.fullPath) + + linkWindow.once('ready-to-show', () => { + linkWindow.show() + linkWindow.maximize() + }) + linkWindow.on('closed', () => { + linkWindow = null }) } @@ -162,18 +163,18 @@ app.on('ready', () => { createLoginWindow() } mainWindow.destroy() + mainWindow = null loginWindow.show() loginWindow.focus() }) //打开作业窗口 - ipcMain.on('openWork', (e, data) => { - createWork(data) + ipcMain.on('openWindow', (e, data) => { + createLinkWin(data) }) - // zdg: 创建工具窗口-如 悬浮球 - Tool() - // 打开-登录窗口 + createLoginWindow() + app.on('activate', function () { if (BrowserWindow.getAllWindows().length === 0) createLoginWindow() }) diff --git a/src/main/update.js b/src/main/update.js new file mode 100644 index 0000000..d59d155 --- /dev/null +++ b/src/main/update.js @@ -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 \ No newline at end of file diff --git a/src/renderer/src/api/file/index.js b/src/renderer/src/api/file/index.js index d4394ac..5bfe721 100644 --- a/src/renderer/src/api/file/index.js +++ b/src/renderer/src/api/file/index.js @@ -9,6 +9,13 @@ export const getSmarttalkPage = (params) => { }) } +export const getPrepareById = (id) => { + return request({ + url: '/smarttalk/file/' + id, + method: 'get' + }) +} + export function deleteSmarttalk(id) { return request({ url: '/smarttalk/file/' + id, diff --git a/src/renderer/src/assets/iconfont/iconfont.css b/src/renderer/src/assets/iconfont/iconfont.css index 7568730..be9c855 100644 --- a/src/renderer/src/assets/iconfont/iconfont.css +++ b/src/renderer/src/assets/iconfont/iconfont.css @@ -1,9 +1,9 @@ @font-face { font-family: "iconfont"; /* Project id 2794390 */ - src: url('iconfont.woff2?t=1721798279074') format('woff2'), - url('iconfont.woff?t=1721798279074') format('woff'), - url('iconfont.ttf?t=1721798279074') format('truetype'), - url('iconfont.svg?t=1721798279074#iconfont') format('svg'); + src: url('iconfont.woff2?t=1721698955462') format('woff2'), + url('iconfont.woff?t=1721698955462') format('woff'), + url('iconfont.ttf?t=1721698955462') format('truetype'), + url('iconfont.svg?t=1721698955462#iconfont') format('svg'); } .iconfont { @@ -14,22 +14,6 @@ -moz-osx-font-smoothing: grayscale; } -.icon-xiayiye:before { - content: "\e68b"; -} - -.icon-shangyiye:before { - content: "\e68e"; -} - -.icon-shuangye:before { - content: "\e64e"; -} - -.icon-danyemoban:before { - content: "\e859"; -} - .icon-lingdang:before { content: "\e613"; } diff --git a/src/renderer/src/assets/iconfont/iconfont.js b/src/renderer/src/assets/iconfont/iconfont.js index 2d957ee..e0e21f1 100644 --- a/src/renderer/src/assets/iconfont/iconfont.js +++ b/src/renderer/src/assets/iconfont/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_2794390='',function(l){var h=(h=document.getElementsByTagName("script"))[h.length-1],v=h.getAttribute("data-injectcss"),h=h.getAttribute("data-disable-injectsvg");if(!h){var c,a,t,z,p,i=function(h,v){v.parentNode.insertBefore(h,v)};if(v&&!l.__iconfont__svg__cssinject__){l.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(h){console&&console.log(h)}}c=function(){var h,v=document.createElement("div");v.innerHTML=l._iconfont_svg_string_2794390,(v=v.getElementsByTagName("svg")[0])&&(v.setAttribute("aria-hidden","true"),v.style.position="absolute",v.style.width=0,v.style.height=0,v.style.overflow="hidden",v=v,(h=document.body).firstChild?i(v,h.firstChild):h.appendChild(v))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(c,0):(a=function(){document.removeEventListener("DOMContentLoaded",a,!1),c()},document.addEventListener("DOMContentLoaded",a,!1)):document.attachEvent&&(t=c,z=l.document,p=!1,d(),z.onreadystatechange=function(){"complete"==z.readyState&&(z.onreadystatechange=null,M())})}function M(){p||(p=!0,t())}function d(){try{z.documentElement.doScroll("left")}catch(h){return void setTimeout(d,50)}M()}}(window); \ No newline at end of file +window._iconfont_svg_string_2794390='',function(l){var h=(h=document.getElementsByTagName("script"))[h.length-1],v=h.getAttribute("data-injectcss"),h=h.getAttribute("data-disable-injectsvg");if(!h){var c,a,t,z,i,p=function(h,v){v.parentNode.insertBefore(h,v)};if(v&&!l.__iconfont__svg__cssinject__){l.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(h){console&&console.log(h)}}c=function(){var h,v=document.createElement("div");v.innerHTML=l._iconfont_svg_string_2794390,(v=v.getElementsByTagName("svg")[0])&&(v.setAttribute("aria-hidden","true"),v.style.position="absolute",v.style.width=0,v.style.height=0,v.style.overflow="hidden",v=v,(h=document.body).firstChild?p(v,h.firstChild):h.appendChild(v))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(c,0):(a=function(){document.removeEventListener("DOMContentLoaded",a,!1),c()},document.addEventListener("DOMContentLoaded",a,!1)):document.attachEvent&&(t=c,z=l.document,i=!1,d(),z.onreadystatechange=function(){"complete"==z.readyState&&(z.onreadystatechange=null,M())})}function M(){i||(i=!0,t())}function d(){try{z.documentElement.doScroll("left")}catch(h){return void setTimeout(d,50)}M()}}(window); \ No newline at end of file diff --git a/src/renderer/src/assets/iconfont/iconfont.json b/src/renderer/src/assets/iconfont/iconfont.json index c101414..7cec3f4 100644 --- a/src/renderer/src/assets/iconfont/iconfont.json +++ b/src/renderer/src/assets/iconfont/iconfont.json @@ -5,34 +5,6 @@ "css_prefix_text": "icon-", "description": "", "glyphs": [ - { - "icon_id": "694110", - "name": "下一页", - "font_class": "xiayiye", - "unicode": "e68b", - "unicode_decimal": 59019 - }, - { - "icon_id": "694115", - "name": "上一页", - "font_class": "shangyiye", - "unicode": "e68e", - "unicode_decimal": 59022 - }, - { - "icon_id": "930693", - "name": "双页", - "font_class": "shuangye", - "unicode": "e64e", - "unicode_decimal": 58958 - }, - { - "icon_id": "2144697", - "name": "单页模板", - "font_class": "danyemoban", - "unicode": "e859", - "unicode_decimal": 59481 - }, { "icon_id": "17990800", "name": "铃铛", diff --git a/src/renderer/src/assets/iconfont/iconfont.svg b/src/renderer/src/assets/iconfont/iconfont.svg index 62cba2a..73737de 100644 --- a/src/renderer/src/assets/iconfont/iconfont.svg +++ b/src/renderer/src/assets/iconfont/iconfont.svg @@ -14,14 +14,6 @@ /> - - - - - - - - diff --git a/src/renderer/src/assets/iconfont/iconfont.ttf b/src/renderer/src/assets/iconfont/iconfont.ttf index 57bd33d..8a4ce47 100644 Binary files a/src/renderer/src/assets/iconfont/iconfont.ttf and b/src/renderer/src/assets/iconfont/iconfont.ttf differ diff --git a/src/renderer/src/assets/iconfont/iconfont.woff b/src/renderer/src/assets/iconfont/iconfont.woff index aa0a6b7..dd9fc0b 100644 Binary files a/src/renderer/src/assets/iconfont/iconfont.woff and b/src/renderer/src/assets/iconfont/iconfont.woff differ diff --git a/src/renderer/src/assets/iconfont/iconfont.woff2 b/src/renderer/src/assets/iconfont/iconfont.woff2 index 3635fac..44bed3c 100644 Binary files a/src/renderer/src/assets/iconfont/iconfont.woff2 and b/src/renderer/src/assets/iconfont/iconfont.woff2 differ diff --git a/src/renderer/src/components/choose-textbook/index.vue b/src/renderer/src/components/choose-textbook/index.vue index cbaf606..3f56bfe 100644 --- a/src/renderer/src/components/choose-textbook/index.vue +++ b/src/renderer/src/components/choose-textbook/index.vue @@ -64,6 +64,8 @@ const defaultProps = { const curBookId = ref(-1) //当前教材名称 const curBookName = ref('') +//当前教材封面图 +const curBookImg = ref('') // 上册 const volumeOne = ref([]) // 下册 @@ -110,9 +112,10 @@ const getSubjectContent = async () => { } //选择教材 -const changeBook = ({ id, itemtitle }) => { +const changeBook = ({ id, itemtitle, avartar }) => { curBookId.value = id curBookName.value = itemtitle + curBookImg.value = BaseUrl + avartar getTreeData() setTimeout(() => { dialogVisible.value = false @@ -144,7 +147,8 @@ const emitChangeBook = () => { const data = { textBook: { curBookId: curBookId.value, - curBookName: curBookName.value + curBookName: curBookName.value, + curBookImg: curBookImg.value }, node: curNode } @@ -236,6 +240,7 @@ const getSubject = async () => { // 默认第一个 curBookName.value = subjectList.value[0].itemtitle curBookId.value = subjectList.value[0].id + curBookImg.value = BaseUrl + subjectList.value[0].avartar } @@ -264,7 +269,8 @@ const handleNodeClick = (data, node) => { let curData = { textBook: { curBookId: curBookId.value, - curBookName: curBookName.value + curBookName: curBookName.value, + curBookImg: curBookImg.value }, node: toRaw(currentNode) } diff --git a/src/renderer/src/components/select-subject/index.vue b/src/renderer/src/components/select-subject/index.vue index d70c423..9071092 100644 --- a/src/renderer/src/components/select-subject/index.vue +++ b/src/renderer/src/components/select-subject/index.vue @@ -79,10 +79,6 @@ const subjectList = ref([]) const allSubject = ref([]) const dialogVisible = ref(false) -watch(() => props.modelValue, (newVal) => { - dialogVisible.value = newVal -}) - //切换年级 const changeGrade = ()=>{ // 切换年级 过滤出对应学科数据 @@ -120,8 +116,13 @@ const editUserInfo = async () =>{ emit('onSuccess') } +watch(() => props.modelValue, (newVal) => { + dialogVisible.value = newVal + if(newVal){ + getSubject() + } +}) -onMounted(getSubject) diff --git a/src/renderer/src/layout/components/Header.vue b/src/renderer/src/layout/components/Header.vue index 9bdb708..e4642b3 100644 --- a/src/renderer/src/layout/components/Header.vue +++ b/src/renderer/src/layout/components/Header.vue @@ -113,9 +113,6 @@ const emits = defineEmits(['setLayout']) function setLayout() { emits('setLayout'); } -watch(()=> userStore.avatar,() => { - userImg.value = userStore.avatar; -},{deep:true}) diff --git a/src/renderer/src/views/prepare/container/file-list-item.vue b/src/renderer/src/views/prepare/container/file-list-item.vue index 55c4124..794210e 100644 --- a/src/renderer/src/views/prepare/container/file-list-item.vue +++ b/src/renderer/src/views/prepare/container/file-list-item.vue @@ -100,10 +100,10 @@ import { Check, UploadFilled, Switch } from '@element-plus/icons-vue' @@ -321,6 +297,7 @@ export default { height: 100%; .page-right { + overflow: hidden; position: relative; min-width: 0; flex: 1; @@ -332,6 +309,55 @@ export default { display: flex; 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 { height: 60px; width: 100%; @@ -340,6 +366,7 @@ export default { flex-wrap: wrap; justify-content: space-between; padding: 0 20px; + } .prepare-body-main { diff --git a/src/renderer/src/views/profile/index.vue b/src/renderer/src/views/profile/index.vue index 54e3ae2..c70b229 100644 --- a/src/renderer/src/views/profile/index.vue +++ b/src/renderer/src/views/profile/index.vue @@ -99,6 +99,7 @@ const state = reactive({ function getUser() { getUserProfile().then((response) => { + response.data.avatar = import.meta.env.VITE_APP_BASE_API + response.data.avatar state.user = response.data state.roleGroup = response.roleGroup state.postGroup = response.postGroup diff --git a/src/renderer/src/views/profile/userAvatar.vue b/src/renderer/src/views/profile/userAvatar.vue index c8c0be7..89965ca 100644 --- a/src/renderer/src/views/profile/userAvatar.vue +++ b/src/renderer/src/views/profile/userAvatar.vue @@ -84,7 +84,7 @@ const title = ref('修改头像') //图片裁剪数据 const options = reactive({ - img: userStore.avatar, // 裁剪图片的地址 + img: userStore.user.avatar, // 裁剪图片的地址 autoCrop: true, // 是否默认生成截图框 autoCropWidth: 200, // 默认生成截图框宽度 autoCropHeight: 200, // 默认生成截图框高度 @@ -155,7 +155,7 @@ function uploadImg() { uploadAvatar(formData).then((response) => { open.value = false options.img = import.meta.env.VITE_APP_BASE_API + response.imgUrl - userStore.avatar = options.img + userStore.user.avatar = options.img ElMessage({ message: '上传成功', type: 'success', diff --git a/src/renderer/src/views/resource/container/resoure-search.vue b/src/renderer/src/views/resource/container/resoure-search.vue index 11cd9ba..7272c0f 100644 --- a/src/renderer/src/views/resource/container/resoure-search.vue +++ b/src/renderer/src/views/resource/container/resoure-search.vue @@ -8,12 +8,13 @@ }} - + -
@@ -22,7 +23,7 @@ {{ - item.label }} + item.label }}
@@ -58,7 +59,8 @@ const sourceStore = useResoureStore() .query-row { justify-content: space-between; - .row-left{ + + .row-left { align-items: center; } } @@ -70,11 +72,12 @@ const sourceStore = useResoureStore() margin: 0 10px; } - + } } -.el-button.is-round{ + +.el-button.is-round { padding: 3px 15px; font-size: 13px; } diff --git a/src/renderer/src/views/resource/index.vue b/src/renderer/src/views/resource/index.vue index 2dd57e8..8d11914 100644 --- a/src/renderer/src/views/resource/index.vue +++ b/src/renderer/src/views/resource/index.vue @@ -6,7 +6,7 @@
- + 新建资源 @@ -27,7 +27,8 @@ import ResoureList from './container/resoure-list.vue' import uploadDialog from '@/components/upload-dialog/index.vue' import uploaderState from '@/store/modules/uploader' import { createTools } from '@/utils/tool' - +import { hasPermission } from '@/utils/hasPermission' +// const sourceStore = useResoureStore() const isDialogOpen = ref(false) @@ -75,17 +76,20 @@ const submitFile = (data) => { item.fileData = fileData item.callback = fileCallBack }) - // console.log(fileList) uploaderState().pushFile(fileList) } const fileCallBack = (res) => { - console.log(res) if (res.code == 200) { sourceStore.handleQuery() } } + +onMounted(()=>{ + sourceStore.getCreate() +}) +