diff --git a/electron-vue-template/electron-builder.json b/electron-vue-template/electron-builder.json index dc8013d..5c02c99 100644 --- a/electron-vue-template/electron-builder.json +++ b/electron-vue-template/electron-builder.json @@ -7,7 +7,9 @@ "compression": "maximum", "asarUnpack": [ "public/jre/**/*", - "public/icon/**/*", + "public/icon/icon.png", + "public/icon/image.png", + "public/icon/img.png", "public/image/**/*", "public/splash.html", "public/config/**/*" @@ -48,7 +50,9 @@ "to": "public", "filter": [ "jre/**/*", - "icon/**/*", + "icon/icon.png", + "icon/image.png", + "icon/img.png", "image/**/*", "splash.html", "config/**/*", diff --git a/electron-vue-template/public/icon/amazon.png b/electron-vue-template/public/icon/amazon.png new file mode 100644 index 0000000..b5100c2 Binary files /dev/null and b/electron-vue-template/public/icon/amazon.png differ diff --git a/electron-vue-template/public/icon/rakuten.png b/electron-vue-template/public/icon/rakuten.png new file mode 100644 index 0000000..3271000 Binary files /dev/null and b/electron-vue-template/public/icon/rakuten.png differ diff --git a/electron-vue-template/public/icon/zebra.png b/electron-vue-template/public/icon/zebra.png new file mode 100644 index 0000000..53f0cd4 Binary files /dev/null and b/electron-vue-template/public/icon/zebra.png differ diff --git a/electron-vue-template/src/main/main.ts b/electron-vue-template/src/main/main.ts index b77ad9d..84f627a 100644 --- a/electron-vue-template/src/main/main.ts +++ b/electron-vue-template/src/main/main.ts @@ -217,12 +217,12 @@ function startSpringBoot() { openAppIfNotOpened(); } }, 15000); - } catch (error) { dialog.showErrorBox('启动异常', `无法启动应用: ${error}`); app.quit(); } } + startSpringBoot(); function stopSpringBoot() { if (!springProcess) return; @@ -362,7 +362,7 @@ app.whenReady().then(() => { // setTimeout(() => { // openAppIfNotOpened(); - // }, 2000); + // }, 100); app.on('activate', () => { if (mainWindow && !mainWindow.isDestroyed()) { diff --git a/electron-vue-template/src/renderer/App.vue b/electron-vue-template/src/renderer/App.vue index 4ceb0ac..3675586 100644 --- a/electron-vue-template/src/renderer/App.vue +++ b/electron-vue-template/src/renderer/App.vue @@ -19,6 +19,10 @@ import UpdateDialog from './components/common/UpdateDialog.vue' import SettingsDialog from './components/common/SettingsDialog.vue' import TrialExpiredDialog from './components/common/TrialExpiredDialog.vue' import AccountManager from './components/common/AccountManager.vue' +// 导入平台图标 +import rakutenIcon from '/icon/rakuten.png' +import amazonIcon from '/icon/amazon.png' +import zebraIcon from '/icon/zebra.png' const dashboardsMap: Record = { rakuten: RakutenDashboard, @@ -116,9 +120,9 @@ const currentVersion = ref('') // 菜单配置 - 复刻ERP客户端格式 const menuConfig = [ - {key: 'rakuten', name: 'Rakuten', index: 'rakuten', icon: 'R'}, - {key: 'amazon', name: 'Amazon', index: 'amazon', icon: 'A'}, - {key: 'zebra', name: 'Zebra', index: 'zebra', icon: 'Z'}, + {key: 'rakuten', name: 'Rakuten', index: 'rakuten', icon: 'R', iconImage: rakutenIcon}, + {key: 'amazon', name: 'Amazon', index: 'amazon', icon: 'A', iconImage: amazonIcon}, + {key: 'zebra', name: 'Zebra', index: 'zebra', icon: 'Z', iconImage: zebraIcon}, {key: 'shopee', name: 'Shopee', index: 'shopee', icon: 'S'}, ] @@ -589,9 +593,13 @@ onUnmounted(() => { :class="{ active: activeMenu === item.key }" @click="handleMenuSelect(item.key)" > - {{ item.icon }}{{ - item.name - }} + + + + + + {{ item.name }} + @@ -812,7 +820,6 @@ onUnmounted(() => { width: 90px; object-fit: contain; - background: #ffffff; } .menu-group-title { @@ -843,8 +850,8 @@ onUnmounted(() => { } .menu-item.active { - background: #ecf5ff !important; - color: #409EFF !important; + background: rgba(0, 0, 0, 0.1) !important; + /* color: #409EFF !important; */ } .menu-text { @@ -868,17 +875,10 @@ onUnmounted(() => { color: #fff; } -.menu-icon[data-k="rakuten"] { - background: #BF0000; -} - -.menu-icon[data-k="amazon"] { - background: #FF9900; - color: #1A1A1A; -} - -.menu-icon[data-k="zebra"] { - background: #34495e; +.menu-icon-img { + width: 100%; + height: 100%; + object-fit: contain; } .menu-icon[data-k="shopee"] { @@ -1003,7 +1003,7 @@ onUnmounted(() => { justify-content: space-between; padding: 10px 12px; box-sizing: border-box; - background: linear-gradient(90deg, #FFF7CC 0%, #FFEB80 100%); + background: #BAE0FF; box-shadow: 0 2px 8px rgba(255, 215, 0, 0.15); transition: all 0.3s ease; position: relative; @@ -1024,7 +1024,7 @@ onUnmounted(() => { .vip-status-card.vip-active, .vip-status-card.vip-normal, .vip-status-card.vip-warning { - background: linear-gradient(90deg, #FFF7CC 0%, #FFEB80 100%); + background: #BAE0FF; box-shadow: 0 2px 8px rgba(255, 215, 0, 0.15); } @@ -1046,15 +1046,16 @@ onUnmounted(() => { .vip-status-text { font-size: 13px; font-weight: 600; - color: #8B6914; + color: #001D66; text-align: left; letter-spacing: 0.3px; } .vip-expire-date { font-size: 10px; - color: #A67C00; + color: #001D66; line-height: 1.3; + text-align: left; opacity: 0.9; } diff --git a/electron-vue-template/src/renderer/components/amazon/AmazonDashboard.vue b/electron-vue-template/src/renderer/components/amazon/AmazonDashboard.vue index 4e29a76..cd03b1b 100644 --- a/electron-vue-template/src/renderer/components/amazon/AmazonDashboard.vue +++ b/electron-vue-template/src/renderer/components/amazon/AmazonDashboard.vue @@ -270,10 +270,8 @@ async function openGenmaiSpirit() { genmaiLoading.value = true try { await systemApi.openGenmaiSpirit(selectedGenmaiAccountId.value) - showMessage('跟卖精灵正在启动,请稍候...', 'success') - setTimeout(() => { genmaiLoading.value = false }, 3000) - } catch (error: any) { - showMessage(error.message || '启动失败', 'error') + showMessage('跟卖精灵已打开', 'success') + } finally { genmaiLoading.value = false } } @@ -390,7 +388,7 @@ onMounted(async () => {
2
启动服务
-
请确保设备已安装Chrome浏览器,否则服务将无法启动。打开跟卖精灵将关闭Chrome浏览器进程。首次启动需初始化浏览器驱动,可能需要1-3分钟。
+
请确保设备已安装Chrome浏览器,否则服务将无法启动。打开跟卖精灵将关闭Chrome浏览器进程。
{ @click="openGenmaiSpirit" > 启动服务 - 启动中... + 启动中...
@@ -679,7 +677,7 @@ onMounted(async () => { .price { color: #e6a23c; font-weight: 600; } .table-loading { position: absolute; inset: 0; background: rgba(255, 255, 255, 0.95); display: flex; flex-direction: column; justify-content: center; align-items: center; font-size: 14px; color: #606266; } .spinner { font-size: 24px; animation: spin 1s linear infinite; margin-bottom: 8px; } -.action-buttons .spinner { font-size: 14px; margin-bottom: 0; display: inline-block; } +.inline-spinner { display: inline-block; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .pagination-fixed { flex-shrink: 0; padding: 8px 12px 0 12px; background: #fff; display: flex; justify-content: flex-end; } .pagination-fixed :deep(.el-pager li.is-active) { border: 1px solid #1677FF; border-radius: 4px; color: #1677FF; background: #fff; } @@ -696,4 +694,4 @@ onMounted(async () => { export default { name: 'AmazonDashboard', } - \ No newline at end of file + diff --git a/electron-vue-template/src/renderer/public/icon/amazon.png b/electron-vue-template/src/renderer/public/icon/amazon.png new file mode 100644 index 0000000..b5100c2 Binary files /dev/null and b/electron-vue-template/src/renderer/public/icon/amazon.png differ diff --git a/electron-vue-template/src/renderer/public/icon/icon.png b/electron-vue-template/src/renderer/public/icon/icon.png index c756ed4..f94b10c 100644 Binary files a/electron-vue-template/src/renderer/public/icon/icon.png and b/electron-vue-template/src/renderer/public/icon/icon.png differ diff --git a/electron-vue-template/src/renderer/public/icon/rakuten.png b/electron-vue-template/src/renderer/public/icon/rakuten.png new file mode 100644 index 0000000..3271000 Binary files /dev/null and b/electron-vue-template/src/renderer/public/icon/rakuten.png differ diff --git a/electron-vue-template/src/renderer/public/icon/zebra.png b/electron-vue-template/src/renderer/public/icon/zebra.png new file mode 100644 index 0000000..53f0cd4 Binary files /dev/null and b/electron-vue-template/src/renderer/public/icon/zebra.png differ diff --git a/erp_client_sb/pom.xml b/erp_client_sb/pom.xml index ffdaa17..b23a600 100644 --- a/erp_client_sb/pom.xml +++ b/erp_client_sb/pom.xml @@ -95,6 +95,11 @@ selenium-java 4.23.0 + + io.github.bonigarcia + webdrivermanager + 5.9.2 + diff --git a/erp_client_sb/src/main/java/com/tashow/erp/config/AsyncConfig.java b/erp_client_sb/src/main/java/com/tashow/erp/config/AsyncConfig.java deleted file mode 100644 index c6b5b9c..0000000 --- a/erp_client_sb/src/main/java/com/tashow/erp/config/AsyncConfig.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.tashow.erp.config; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.EnableAsync; - -@Configuration -@EnableAsync -public class AsyncConfig { -} - diff --git a/erp_client_sb/src/main/java/com/tashow/erp/config/ChromeDriverPreloader.java b/erp_client_sb/src/main/java/com/tashow/erp/config/ChromeDriverPreloader.java new file mode 100644 index 0000000..5d8b2a1 --- /dev/null +++ b/erp_client_sb/src/main/java/com/tashow/erp/config/ChromeDriverPreloader.java @@ -0,0 +1,58 @@ +package com.tashow.erp.config; + +import io.github.bonigarcia.wdm.WebDriverManager; +import lombok.extern.slf4j.Slf4j; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import java.net.URL; + +/** + * ChromeDriver预加载器 + * 在应用启动时后台下载ChromeDriver,避免用户首次使用时等待 + * 使用国内镜像源加速下载 + */ +@Slf4j +@Component +@Order(2) // 在DatabaseConfig之后运行 +public class ChromeDriverPreloader implements ApplicationRunner { + + @Override + public void run(ApplicationArguments args) { + // 使用后台线程执行,不阻塞应用启动 + Thread preloadThread = new Thread(() -> { + try { + log.info("开始预加载ChromeDriver驱动(使用国内镜像加速)..."); + + // 配置WebDriverManager使用国内镜像源 + WebDriverManager.chromedriver() + .driverRepositoryUrl(new URL("https://registry.npmmirror.com/-/binary/chromedriver/")) + .setup(); + + log.info("ChromeDriver驱动下载完成,开始验证..."); + + // 快速验证驱动可用性 + ChromeOptions options = new ChromeOptions(); + options.addArguments("--headless"); // 无头模式,不显示浏览器 + options.addArguments("--disable-gpu"); + options.addArguments("--no-sandbox"); + + ChromeDriver driver = new ChromeDriver(options); + driver.quit(); // 立即关闭 + + log.info("ChromeDriver驱动预加载成功"); + + } catch (Exception e) { + // 预加载失败不影响应用启动,第一次使用时会自动下载 + log.warn("ChromeDriver驱动预加载失败(不影响使用): {}", e.getMessage()); + } + }, "ChromeDriver-Preloader"); + + preloadThread.setDaemon(true); // 设置为守护线程 + preloadThread.start(); + } +} + diff --git a/erp_client_sb/src/main/java/com/tashow/erp/controller/SystemController.java b/erp_client_sb/src/main/java/com/tashow/erp/controller/SystemController.java index f3cc18a..c0d7d8f 100644 --- a/erp_client_sb/src/main/java/com/tashow/erp/controller/SystemController.java +++ b/erp_client_sb/src/main/java/com/tashow/erp/controller/SystemController.java @@ -84,9 +84,14 @@ public class SystemController { @PostMapping("/genmai/open") public JsonData openGenmaiWebsite(@RequestParam(required = false) Long accountId, HttpServletRequest request) { - String username = com.tashow.erp.utils.JwtUtil.getUsernameFromRequest(request); - genmaiService.openGenmaiWebsite(accountId, username); - return JsonData.buildSuccess("跟卖精灵正在启动"); + try { + String username = com.tashow.erp.utils.JwtUtil.getUsernameFromRequest(request); + genmaiService.openGenmaiWebsite(accountId, username); + return JsonData.buildSuccess("跟卖精灵已打开"); + } catch (Exception e) { + logger.error("打开跟卖精灵失败", e); + return JsonData.buildError(e.getMessage() != null ? e.getMessage() : "打开跟卖精灵失败"); + } } @GetMapping("/proxy/image") diff --git a/erp_client_sb/src/main/java/com/tashow/erp/service/impl/ChromeDriverPreloader.java b/erp_client_sb/src/main/java/com/tashow/erp/service/impl/ChromeDriverPreloader.java deleted file mode 100644 index 1eb9f7f..0000000 --- a/erp_client_sb/src/main/java/com/tashow/erp/service/impl/ChromeDriverPreloader.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.tashow.erp.service.impl; -import jakarta.annotation.PostConstruct; -import org.openqa.selenium.chrome.ChromeDriver; -import org.openqa.selenium.chrome.ChromeOptions; -import org.springframework.stereotype.Component; - -@Component -public class ChromeDriverPreloader { - @PostConstruct - public void preloadDriver() { - new Thread(() -> { - try { - ChromeOptions options = new ChromeOptions(); - options.addArguments("--headless", "--disable-gpu"); - ChromeDriver driver = new ChromeDriver(options); - driver.quit(); - } catch (Exception ignored) {} - }).start(); - } -} - diff --git a/erp_client_sb/src/main/java/com/tashow/erp/service/impl/GenmaiServiceImpl.java b/erp_client_sb/src/main/java/com/tashow/erp/service/impl/GenmaiServiceImpl.java index 5154ced..74a1c96 100644 --- a/erp_client_sb/src/main/java/com/tashow/erp/service/impl/GenmaiServiceImpl.java +++ b/erp_client_sb/src/main/java/com/tashow/erp/service/impl/GenmaiServiceImpl.java @@ -2,14 +2,15 @@ package com.tashow.erp.service.impl; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.qiniu.util.UrlUtils; +import io.github.bonigarcia.wdm.WebDriverManager; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.*; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; +import java.net.URL; import java.util.List; import java.util.Map; @@ -20,27 +21,29 @@ public class GenmaiServiceImpl { private final RestTemplate restTemplate = new RestTemplate(); private final ObjectMapper objectMapper = new ObjectMapper(); - @Async - public void openGenmaiWebsite(Long accountId, String username) { - try { - String token = getAndValidateToken(accountId, username); - Runtime.getRuntime().exec("taskkill /f /im chrome.exe"); - Thread.sleep(1000); - - ChromeOptions options = new ChromeOptions(); - String systemUser = System.getProperty("user.name"); - char firstChar = systemUser.charAt(0); - char flipped = Character.isUpperCase(firstChar) ? Character.toLowerCase(firstChar) : Character.toUpperCase(firstChar); - String chromeUserData = System.getProperty("user.home") - .replace(systemUser, UrlUtils.urlEncode(flipped + systemUser.substring(1))) - + "\\AppData\\Local\\Google\\Chrome\\User Data"; - options.addArguments("user-data-dir=" + chromeUserData.toLowerCase(), "profile-directory=Default"); - - ChromeDriver driver = new ChromeDriver(options); - driver.get("https://www.genmaijl.com/#/profile"); - ((JavascriptExecutor) driver).executeScript("localStorage.setItem('token','" + token + "')"); - driver.navigate().refresh(); - } catch (Exception ignored) {} + public void openGenmaiWebsite(Long accountId, String username) throws Exception { + WebDriverManager.chromedriver() + .driverRepositoryUrl(new URL("https://registry.npmmirror.com/-/binary/chromedriver/")) + .setup(); + + String token = getAndValidateToken(accountId, username); + Runtime.getRuntime().exec("taskkill /f /im chrome.exe"); + Thread.sleep(1000); + + + ChromeOptions options = new ChromeOptions(); + String systemUser = System.getProperty("user.name"); + char firstChar = systemUser.charAt(0); + char flipped = Character.isUpperCase(firstChar) ? Character.toLowerCase(firstChar) : Character.toUpperCase(firstChar); + String chromeUserData = System.getProperty("user.home") + .replace(systemUser, UrlUtils.urlEncode(flipped + systemUser.substring(1))) + + "\\AppData\\Local\\Google\\Chrome\\User Data"; + options.addArguments("user-data-dir=" + chromeUserData.toLowerCase(), "profile-directory=Default"); + + ChromeDriver driver = new ChromeDriver(options); + driver.get("https://www.genmaijl.com/#/profile"); + ((JavascriptExecutor) driver).executeScript("localStorage.setItem('token','" + token + "')"); + driver.navigate().refresh(); } @SuppressWarnings("unchecked") diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/RefreshToken.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/RefreshToken.java new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/RefreshToken.java @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/RefreshTokenMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/RefreshTokenMapper.java new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/RefreshTokenMapper.java @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-system/src/main/resources/mapper/system/RefreshTokenMapper.xml b/ruoyi-system/src/main/resources/mapper/system/RefreshTokenMapper.xml new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/system/RefreshTokenMapper.xml @@ -0,0 +1 @@ + \ No newline at end of file