From 7c7009ffeda98dc7677a8385007643eed833e189 Mon Sep 17 00:00:00 2001 From: zhangzijienbplus <17738440858@163.com> Date: Thu, 6 Nov 2025 14:39:58 +0800 Subject: [PATCH] =?UTF-8?q?feat(electron):=E4=BC=98=E5=8C=96=E5=95=86?= =?UTF-8?q?=E6=A0=87=E7=AD=9B=E6=9F=A5=E9=9D=A2=E6=9D=BF=E4=B8=8E=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E5=8A=A0=E8=BD=BD=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将多个 v-if 条件渲染改为 v-show,提升组件切换性能 - 优化商标任务完成状态判断逻辑,确保准确显示采集完成图标- 调整任务统计数据显示条件,支持零数据展示- 更新 API 配置地址,切换至本地开发环境地址 - 降低 Spring Boot 线程池与数据库连接池配置,适应小规模并发- 禁用 devtools 热部署与 Swagger 接口文档,优化生产环境性能 - 配置 RestTemplate 使用 HttpClient 连接池,增强 HTTP 请求稳定性 - 改进静态资源拷贝脚本,确保 icon 与 image 文件夹正确复制 - 更新 electron-builder 配置,优化资源打包路径与应用图标 - 修改 HTTP 路由规则,明确区分客户端与管理端接口路径- 注册文件协议拦截器,解决生产环境下 icon/image 资源加载问题 - 调整商标 API 接口路径,指向 erp_client_sb服务 -重构 MarkController 控制器,专注 Token 管理功能 - 优化线程池参数,适配低并发业务场景- 强化商标筛查流程控制,完善任务取消与异常处理机制 - 新增方舟精选任务管理接口,实现 Excel 下载与数据解析功能 --- electron-vue-template/electron-builder.json | 13 +- electron-vue-template/scripts/copy-assets.js | 32 +-- electron-vue-template/src/main/main.ts | 30 +-- electron-vue-template/src/main/tray.ts | 4 +- .../src/renderer/api/http.ts | 8 +- .../src/renderer/auto-imports.d.ts | 9 + .../src/renderer/components.d.ts | 31 +++ .../components/amazon/AmazonDashboard.vue | 20 +- .../components/amazon/TrademarkCheckPanel.vue | 196 ++++++++++++------ erp_client_sb/pom.xml | 2 +- .../erp/controller/TrademarkController.java | 6 +- .../service/impl/FangzhouApiServiceImpl.java | 11 +- .../system/service/impl/MarkServiceImpl.java | 7 +- 13 files changed, 255 insertions(+), 114 deletions(-) create mode 100644 electron-vue-template/src/renderer/auto-imports.d.ts create mode 100644 electron-vue-template/src/renderer/components.d.ts diff --git a/electron-vue-template/electron-builder.json b/electron-vue-template/electron-builder.json index 7faa152..7bc94b2 100644 --- a/electron-vue-template/electron-builder.json +++ b/electron-vue-template/electron-builder.json @@ -10,8 +10,7 @@ "public/icon/**/*", "public/image/**/*", "public/splash.html", - "public/config/**/*", - "renderer/**/*" + "public/config/**/*" ], "directories": { "output": "dist" @@ -37,7 +36,15 @@ { "from": "build/renderer", "to": "renderer", - "filter": ["**/*"] + "filter": [ + "**/*", + "!icon/**/*", + "!image/**/*", + "!jre/**/*", + "!config/**/*", + "!*.jar", + "!splash.html" + ] }, { "from": "public", diff --git a/electron-vue-template/scripts/copy-assets.js b/electron-vue-template/scripts/copy-assets.js index bd5d848..9e1b29c 100644 --- a/electron-vue-template/scripts/copy-assets.js +++ b/electron-vue-template/scripts/copy-assets.js @@ -4,23 +4,25 @@ const FileSystem = require('fs-extra'); async function copyAssets() { console.log('Copying static assets from public directory...'); - const publicDir = Path.join(__dirname, '..', 'public'); - const buildRendererDir = Path.join(__dirname, '..', 'build', 'renderer'); + // 注释:icon 和 image 资源已统一由 public 目录管理 + // electron-builder 会直接从 public 打包这些资源到 app.asar.unpacked + // 不需要复制到 build/renderer,避免重复打包导致体积增大 - // 确保 build/renderer 下的 icon 和 image 目录存在且是最新的 - // 这样打包后 renderer/icon 和 renderer/image 会包含所有图标 - await FileSystem.copy( - Path.join(publicDir, 'icon'), - Path.join(buildRendererDir, 'icon'), - { overwrite: true } - ); - await FileSystem.copy( - Path.join(publicDir, 'image'), - Path.join(buildRendererDir, 'image'), - { overwrite: true } - ); + // const publicDir = Path.join(__dirname, '..', 'public'); + // const buildRendererDir = Path.join(__dirname, '..', 'build', 'renderer'); - console.log('Static assets copied to build/renderer successfully!'); + // await FileSystem.copy( + // Path.join(publicDir, 'icon'), + // Path.join(buildRendererDir, 'icon'), + // { overwrite: true } + // ); + // await FileSystem.copy( + // Path.join(publicDir, 'image'), + // Path.join(buildRendererDir, 'image'), + // { overwrite: true } + // ); + + console.log('Static assets copy skipped (resources managed by public directory).'); } module.exports = copyAssets; \ No newline at end of file diff --git a/electron-vue-template/src/main/main.ts b/electron-vue-template/src/main/main.ts index c0e49d9..6bc4c7f 100644 --- a/electron-vue-template/src/main/main.ts +++ b/electron-vue-template/src/main/main.ts @@ -4,10 +4,9 @@ import {join, dirname, basename, extname} from 'path'; import {spawn, ChildProcess} from 'child_process'; import * as https from 'https'; import * as http from 'http'; +import { fileURLToPath } from 'url'; import { createTray, destroyTray } from './tray'; - const isDev = process.env.NODE_ENV === 'development'; - let springProcess: ChildProcess | null = null; let mainWindow: BrowserWindow | null = null; let splashWindow: BrowserWindow | null = null; @@ -74,7 +73,7 @@ function getJarFilePath(): string { } const getSplashPath = () => getResourcePath('../../public/splash.html', 'public/splash.html'); -const getIconPath = () => getResourcePath('../../public/icon/icon1.png', 'public/icon/icon1.png', '../renderer/icon/icon1.png'); +const getIconPath = () => getResourcePath('../../public/icon/icon1.png', 'public/icon/icon1.png'); const getLogbackConfigPath = () => getResourcePath('../../public/config/logback.xml', 'public/config/logback.xml'); function getDataDirectoryPath(): string { @@ -211,7 +210,7 @@ function startSpringBoot() { } } - // startSpringBoot(); + startSpringBoot(); function stopSpringBoot() { if (!springProcess) return; try { @@ -305,14 +304,21 @@ if (!gotTheLock) { } app.whenReady().then(() => { - // 注册文件协议拦截器,将 /icon/ 和 /image/ 请求重定向到 public 目录 if (!isDev) { protocol.interceptFileProtocol('file', (request, callback) => { - let url = request.url.substring(8); // 移除 'file:///' + // 使用 fileURLToPath 正确解码 URL,处理空格和特殊字符 + let filePath: string; + try { + filePath = fileURLToPath(request.url); + } catch (e) { + // 如果解码失败,回退到原来的方法 + filePath = decodeURIComponent(request.url.substring(8)); + } // 检查是否是 icon 或 image 资源请求 - if (url.includes('/icon/') || url.includes('/image/')) { - const match = url.match(/\/(icon|image)\/([^?#]+)/); + if (filePath.includes('/icon/') || filePath.includes('\\icon\\') || + filePath.includes('/image/') || filePath.includes('\\image\\')) { + const match = filePath.match(/[/\\](icon|image)[/\\]([^?#]+)/); if (match) { const [, type, filename] = match; const publicPath = join(process.resourcesPath, 'app.asar.unpacked', 'public', type, filename); @@ -323,7 +329,7 @@ app.whenReady().then(() => { } } - callback({ path: url }); + callback({ path: filePath }); }); } @@ -370,9 +376,9 @@ app.whenReady().then(() => { } } //666 - setTimeout(() => { - openAppIfNotOpened(); - }, 100); +// setTimeout(() => { +// openAppIfNotOpened(); +// }, 100); app.on('activate', () => { if (mainWindow && !mainWindow.isDestroyed()) { diff --git a/electron-vue-template/src/main/tray.ts b/electron-vue-template/src/main/tray.ts index cfd1ddc..6d57d69 100644 --- a/electron-vue-template/src/main/tray.ts +++ b/electron-vue-template/src/main/tray.ts @@ -9,9 +9,7 @@ function getIconPath(): string { if (isDev) { return join(__dirname, '../../public/icon/icon1.png') } - const bundledPath = join(process.resourcesPath, 'app.asar.unpacked', 'public/icon/icon1.png') - if (existsSync(bundledPath)) return bundledPath - return join(__dirname, '../renderer/icon/icon1.png') + return join(process.resourcesPath, 'app.asar.unpacked', 'public/icon/icon1.png') } export function createTray(mainWindow: BrowserWindow | null) { diff --git a/electron-vue-template/src/renderer/api/http.ts b/electron-vue-template/src/renderer/api/http.ts index ea133c8..249dbf8 100644 --- a/electron-vue-template/src/renderer/api/http.ts +++ b/electron-vue-template/src/renderer/api/http.ts @@ -1,11 +1,11 @@ export type HttpMethod = 'GET' | 'POST' | 'DELETE'; +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: 'http://8.138.23.49:8085', - RUOYI_BASE: 'http://192.168.1.89:8085', - SSE_URL: 'http://192.168.1.89:8085/monitor/account/events' + RUOYI_BASE, + SSE_URL: `${RUOYI_BASE}/monitor/account/events` } as const; - function resolveBase(path: string): string { // 路由到 ruoyi-admin (8085):仅系统管理和监控相关 if (path.startsWith('/monitor/') || path.startsWith('/system/') || path.startsWith('/tool/banma') || path.startsWith('/tool/genmai')) { diff --git a/electron-vue-template/src/renderer/auto-imports.d.ts b/electron-vue-template/src/renderer/auto-imports.d.ts new file mode 100644 index 0000000..1d89ee8 --- /dev/null +++ b/electron-vue-template/src/renderer/auto-imports.d.ts @@ -0,0 +1,9 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// noinspection JSUnusedGlobalSymbols +// Generated by unplugin-auto-import +export {} +declare global { + +} diff --git a/electron-vue-template/src/renderer/components.d.ts b/electron-vue-template/src/renderer/components.d.ts new file mode 100644 index 0000000..45040ff --- /dev/null +++ b/electron-vue-template/src/renderer/components.d.ts @@ -0,0 +1,31 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +export {} + +declare module 'vue' { + export interface GlobalComponents { + ElButton: typeof import('element-plus/es')['ElButton'] + ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] + ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] + ElDialog: typeof import('element-plus/es')['ElDialog'] + ElDropdown: typeof import('element-plus/es')['ElDropdown'] + ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] + ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] + ElIcon: typeof import('element-plus/es')['ElIcon'] + ElImage: typeof import('element-plus/es')['ElImage'] + ElInput: typeof import('element-plus/es')['ElInput'] + ElOption: typeof import('element-plus/es')['ElOption'] + ElPagination: typeof import('element-plus/es')['ElPagination'] + ElProgress: typeof import('element-plus/es')['ElProgress'] + ElRadio: typeof import('element-plus/es')['ElRadio'] + ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] + ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] + ElSelect: typeof import('element-plus/es')['ElSelect'] + ElTable: typeof import('element-plus/es')['ElTable'] + ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] + ElTag: typeof import('element-plus/es')['ElTag'] + } +} diff --git a/electron-vue-template/src/renderer/components/amazon/AmazonDashboard.vue b/electron-vue-template/src/renderer/components/amazon/AmazonDashboard.vue index 8816957..b36f8ee 100644 --- a/electron-vue-template/src/renderer/components/amazon/AmazonDashboard.vue +++ b/electron-vue-template/src/renderer/components/amazon/AmazonDashboard.vue @@ -249,7 +249,7 @@ function handleExportData() {