From c2e1617a99a64b208cbc19284c5c5ca42be6b4d3 Mon Sep 17 00:00:00 2001 From: zhangzijienbplus <17738440858@163.com> Date: Sat, 8 Nov 2025 10:23:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(client):=20=E5=AE=9E=E7=8E=B0=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E5=BC=80=E5=B1=8F=E5=9B=BE=E7=89=87=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 ClientAccount 实体中新增 splashImage 字段用于存储开屏图片URL - 在 ClientAccountController 中添加上传、获取和删除开屏图片的接口 - 集成七牛云存储实现图片上传功能,支持图片格式和大小校验 - 使用 Redis 缓存开屏图片URL,提升访问性能 - 在客户端登录成功后异步加载并保存开屏图片配置 - 新增 splashApi 模块封装开屏图片相关HTTP请求- 在主进程中实现开屏图片配置的持久化存储和读取 - 在设置页面中增加开屏图片管理界面,支持上传、预览和删除操作 - 修改 splash.html 支持动态加载自定义开屏图片 - 调整 CSP 策略允许加载本地和HTTPS图片资源 --- electron-vue-template/public/splash.html | 4 +- electron-vue-template/src/main/main.ts | 40 +++- electron-vue-template/src/main/preload.ts | 4 + .../src/renderer/api/http.ts | 4 +- .../src/renderer/api/splash.ts | 32 ++++ .../components/amazon/TrademarkCheckPanel.vue | 1 - .../renderer/components/auth/LoginDialog.vue | 15 ++ .../components/common/SettingsDialog.vue | 177 ++++++++++++++++++ .../service/impl/FangzhouApiServiceImpl.java | 1 - .../monitor/ClientAccountController.java | 94 +++++++++- .../com/ruoyi/system/domain/BanmaAccount.java | 2 - .../ruoyi/system/domain/ClientAccount.java | 13 ++ .../mapper/system/ClientAccountMapper.xml | 6 +- 13 files changed, 374 insertions(+), 19 deletions(-) create mode 100644 electron-vue-template/src/renderer/api/splash.ts diff --git a/electron-vue-template/public/splash.html b/electron-vue-template/public/splash.html index 92c6270..ff5fd65 100644 --- a/electron-vue-template/public/splash.html +++ b/electron-vue-template/public/splash.html @@ -8,7 +8,7 @@ html, body { height: 100%; margin: 0; } body { background: #fff; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif; - background-image: url('./image/splash_screen.png'); + background-image: var(--splash-image, url('./image/splash_screen.png')); background-repeat: no-repeat; background-position: center; background-size: cover; @@ -21,7 +21,7 @@ - +
diff --git a/electron-vue-template/src/main/main.ts b/electron-vue-template/src/main/main.ts index 6bc4c7f..9aca48f 100644 --- a/electron-vue-template/src/main/main.ts +++ b/electron-vue-template/src/main/main.ts @@ -94,10 +94,13 @@ function getLogDirectoryPath(): string { return logDir; } + interface AppConfig { closeAction?: 'quit' | 'minimize' | 'tray'; autoLaunch?: boolean; launchMinimized?: boolean; + lastUsername?: string; + splashImageUrl?: string; } function getConfigPath(): string { @@ -210,7 +213,7 @@ function startSpringBoot() { } } - startSpringBoot(); + // startSpringBoot(); function stopSpringBoot() { if (!springProcess) return; try { @@ -372,13 +375,26 @@ app.whenReady().then(() => { const splashPath = getSplashPath(); if (existsSync(splashPath)) { + const config = loadConfig(); + const imageUrl = config.splashImageUrl || ''; + console.log('[开屏图片] 启动配置:', { username: config.lastUsername, imageUrl, configPath: getConfigPath() }); + splashWindow.loadFile(splashPath); + + if (imageUrl) { + splashWindow.webContents.once('did-finish-load', () => { + splashWindow?.webContents.executeJavaScript(` + document.body.style.setProperty('--splash-image', "url('${imageUrl}')"); + `).then(() => console.log('[开屏图片] 注入成功:', imageUrl)) + .catch(err => console.error('[开屏图片] 注入失败:', err)); + }); + } } } //666 -// setTimeout(() => { -// openAppIfNotOpened(); -// }, 100); + setTimeout(() => { + openAppIfNotOpened(); + }, 100); app.on('activate', () => { if (mainWindow && !mainWindow.isDestroyed()) { @@ -769,6 +785,22 @@ ipcMain.handle('window-is-maximized', () => { return mainWindow && !mainWindow.isDestroyed() ? mainWindow.isMaximized() : false; }); +// 保存开屏图片配置(用户名 + URL) +ipcMain.handle('save-splash-config', (event, username: string, imageUrl: string) => { + const config = loadConfig(); + config.lastUsername = username; + config.splashImageUrl = imageUrl; + saveConfig(config); + console.log('[开屏图片] 已保存配置:', { username, imageUrl, path: getConfigPath() }); + return { success: true }; +}); + +// 获取开屏图片配置 +ipcMain.handle('get-splash-config', () => { + const config = loadConfig(); + return { username: config.lastUsername || '', imageUrl: config.splashImageUrl || '' }; +}); + async function getFileSize(url: string): Promise { return new Promise((resolve) => { diff --git a/electron-vue-template/src/main/preload.ts b/electron-vue-template/src/main/preload.ts index 0bd3117..a54291b 100644 --- a/electron-vue-template/src/main/preload.ts +++ b/electron-vue-template/src/main/preload.ts @@ -43,6 +43,10 @@ const electronAPI = { windowClose: () => ipcRenderer.invoke('window-close'), windowIsMaximized: () => ipcRenderer.invoke('window-is-maximized'), + // 开屏图片相关 API + saveSplashConfig: (username: string, imageUrl: string) => ipcRenderer.invoke('save-splash-config', username, imageUrl), + getSplashConfig: () => ipcRenderer.invoke('get-splash-config'), + onDownloadProgress: (callback: (progress: any) => void) => { ipcRenderer.removeAllListeners('download-progress') ipcRenderer.on('download-progress', (event, progress) => callback(progress)) diff --git a/electron-vue-template/src/renderer/api/http.ts b/electron-vue-template/src/renderer/api/http.ts index 249dbf8..a6481b3 100644 --- a/electron-vue-template/src/renderer/api/http.ts +++ b/electron-vue-template/src/renderer/api/http.ts @@ -1,6 +1,6 @@ export type HttpMethod = 'GET' | 'POST' | 'DELETE'; -const RUOYI_BASE = 'http://8.138.23.49:8085'; -// const RUOYI_BASE = 'http://192.168.1.89:8085'; +//const RUOYI_BASE = 'http://8.138.23.49:8085'; + const RUOYI_BASE = 'http://192.168.1.89:8085'; export const CONFIG = { CLIENT_BASE: 'http://localhost:8081', RUOYI_BASE, diff --git a/electron-vue-template/src/renderer/api/splash.ts b/electron-vue-template/src/renderer/api/splash.ts new file mode 100644 index 0000000..13ff308 --- /dev/null +++ b/electron-vue-template/src/renderer/api/splash.ts @@ -0,0 +1,32 @@ +import { http } from './http' + +export interface SplashImageResponse { + splashImage: string + url: string +} + +export const splashApi = { + // 上传开屏图片 + async uploadSplashImage(file: File, username: string) { + const formData = new FormData() + formData.append('file', file) + formData.append('username', username) + return http.upload<{ data: { url: string; fileName: string } }>('/monitor/account/splash-image/upload', formData) + }, + + // 获取当前用户的开屏图片 + async getSplashImage(username: string) { + return http.get<{ data: SplashImageResponse }>('/monitor/account/splash-image', { username }) + }, + + // 根据用户名获取开屏图片(用于启动时) + async getSplashImageByUsername(username: string) { + return http.get<{ data: SplashImageResponse }>('/monitor/account/splash-image/by-username', { username }) + }, + + // 删除自定义开屏图片(恢复默认) + async deleteSplashImage(username: string) { + return http.post<{ data: string }>(`/monitor/account/splash-image/delete?username=${username}`) + } +} + diff --git a/electron-vue-template/src/renderer/components/amazon/TrademarkCheckPanel.vue b/electron-vue-template/src/renderer/components/amazon/TrademarkCheckPanel.vue index 2efe0f9..0c999de 100644 --- a/electron-vue-template/src/renderer/components/amazon/TrademarkCheckPanel.vue +++ b/electron-vue-template/src/renderer/components/amazon/TrademarkCheckPanel.vue @@ -359,7 +359,6 @@ async function startTrademarkQuery() { // 其他错误(网络错误等)继续等待 } } - clearInterval(progressTimer) return taskResult } diff --git a/electron-vue-template/src/renderer/components/auth/LoginDialog.vue b/electron-vue-template/src/renderer/components/auth/LoginDialog.vue index 65fb81c..02b9a33 100644 --- a/electron-vue-template/src/renderer/components/auth/LoginDialog.vue +++ b/electron-vue-template/src/renderer/components/auth/LoginDialog.vue @@ -4,6 +4,7 @@ import { ElMessage } from 'element-plus' import { User } from '@element-plus/icons-vue' import { authApi } from '../../api/auth' import { getOrCreateDeviceId } from '../../utils/deviceId' +import { splashApi } from '../../api/splash' interface Props { modelValue: boolean @@ -41,6 +42,9 @@ async function handleAuth() { clientId: deviceId }) + // 保存开屏图片配置(不阻塞登录) + saveSplashConfigInBackground(authForm.value.username) + emit('loginSuccess', { token: loginRes.data.accessToken || loginRes.data.token, permissions: loginRes.data.permissions, @@ -75,6 +79,17 @@ function resetForm() { function showRegister() { emit('showRegister') } + +// 保存开屏图片配置 +async function saveSplashConfigInBackground(username: string) { + try { + const res = await splashApi.getSplashImage(username) + const url = res?.data?.data?.url || res?.data?.url || '' + await (window as any).electronAPI.saveSplashConfig(username, url) + } catch (error) { + console.error('[开屏图片] 保存配置失败:', error) + } +}