diff --git a/electron-vue-template/src/main/main.ts b/electron-vue-template/src/main/main.ts index 4ac6a56..450edd5 100644 --- a/electron-vue-template/src/main/main.ts +++ b/electron-vue-template/src/main/main.ts @@ -229,8 +229,6 @@ function startSpringBoot() { const dataDir = getDataDirectoryPath(); const logDir = getLogDirectoryPath(); const logbackConfigPath = getLogbackConfigPath(); - console.log('[Spring Boot] JAR路径:', jarPath); - console.log('[Spring Boot] Java路径:', javaPath); if (!existsSync(jarPath)) { dialog.showErrorBox('启动失败', `JAR 文件不存在:\n${jarPath}`); app.quit(); @@ -475,9 +473,14 @@ app.whenReady().then(() => { splashWindow.once('ready-to-show', () => splashWindow?.show()); } + // 已手动启动后端 setTimeout(() => { startSpringBoot(); }, 200); + + // setTimeout(() => { + // openAppIfNotOpened(); + // }, 200); app.on('activate', () => { if (mainWindow && !mainWindow.isDestroyed()) { @@ -856,15 +859,7 @@ ipcMain.handle('dev-skip-backend', () => { return { success: false, error: '仅开发模式可用' }; }); -// 开发模式:手动启动后端 -ipcMain.handle('dev-start-backend', () => { - if (isDev) { - console.log('[开发模式] 前端请求启动后端'); - startSpringBoot(); - return { success: true }; - } - return { success: false, error: '仅开发模式可用' }; -}); + // 窗口控制 API ipcMain.handle('window-minimize', () => { diff --git a/electron-vue-template/src/renderer/App.vue b/electron-vue-template/src/renderer/App.vue index 3c98a24..e615ab0 100644 --- a/electron-vue-template/src/renderer/App.vue +++ b/electron-vue-template/src/renderer/App.vue @@ -51,6 +51,7 @@ const showAuthDialog = ref(false) const showRegDialog = ref(false) const zhCnLocale = zhCn const currentUsername = ref('') +const registerTime = ref('') const showDeviceDialog = ref(false) const deviceLoading = ref(false) const devices = ref([]) @@ -220,6 +221,7 @@ async function handleLoginSuccess(data: { vipExpireTime.value = data.expireTime ? new Date(data.expireTime) : null accountType.value = data.accountType || 'trial' deviceTrialExpired.value = data.deviceTrialExpired || false + registerTime.value = data.registerTime || '' const deviceId = await getOrCreateDeviceId() await deviceApi.register({ @@ -249,6 +251,7 @@ async function clearLocalAuth() { removeToken() isAuthenticated.value = false currentUsername.value = '' + registerTime.value = '' userPermissions.value = '' vipExpireTime.value = null deviceTrialExpired.value = false @@ -319,6 +322,7 @@ async function checkAuth() { userPermissions.value = res.data.permissions || '' deviceTrialExpired.value = res.data.deviceTrialExpired || false accountType.value = res.data.accountType || 'trial' + registerTime.value = res.data.registerTime || '' if (res.data.expireTime) { vipExpireTime.value = new Date(res.data.expireTime) @@ -640,15 +644,8 @@ onUnmounted(() => {
用户头像 - 默认头像
@@ -657,7 +654,7 @@ onUnmounted(() => { {{ isAuthenticated ? currentUsername : '登录/注册' }} VIP {{ vipStatus.daysLeft }}天
-
{{ isAuthenticated ? '18659156151' : '登录账号体验完整功能' }}
+
{{ isAuthenticated ? ` ${registerTime ? registerTime.replace('T', ' ').substring(0, 16) : '未知'}` : '登录账号体验完整功能' }}
@@ -903,7 +900,6 @@ onUnmounted(() => { /* 主Logo */ .main-logo { - display: flex; align-items: center; justify-content: center; padding: 8px 0; @@ -929,8 +925,8 @@ onUnmounted(() => { .avatar-wrapper { flex-shrink: 0; - width: 44px; - height: 44px; + width: 40px; + height: 40px; border-radius: 50%; overflow: hidden; background: #fff; @@ -958,7 +954,7 @@ onUnmounted(() => { .user-name-wrapper { display: flex; align-items: center; - gap: 6px; + gap: 4px; min-width: 0; } @@ -968,15 +964,17 @@ onUnmounted(() => { color: #303133; white-space: nowrap; line-height: 1.2; - flex-shrink: 0; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; } .vip-badge { display: inline-flex; align-items: center; justify-content: center; - padding: 0px 5px; - height: 16px; + padding: 0px 3px; + height: 14px; background: #BAE0FF; border: 1px solid rgba(22, 119, 255, 0.05); border-radius: 8px; @@ -1021,7 +1019,8 @@ onUnmounted(() => { .brand-logo { max-width: 100%; max-height: 100%; - object-fit: contain; + object-fit: cover; + border-radius: 12px; } .menu { diff --git a/electron-vue-template/src/renderer/api/http.ts b/electron-vue-template/src/renderer/api/http.ts index 249dbf8..8084ec7 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://192.168.1.89:8085'; export const CONFIG = { CLIENT_BASE: 'http://localhost:8081', RUOYI_BASE, diff --git a/electron-vue-template/src/renderer/api/mark.ts b/electron-vue-template/src/renderer/api/mark.ts index 97f5ab7..6086842 100644 --- a/electron-vue-template/src/renderer/api/mark.ts +++ b/electron-vue-template/src/renderer/api/mark.ts @@ -2,28 +2,28 @@ import { http } from './http' export const markApi = { // 新建任务(调用 erp_client_sb) - newTask(file: File) { + newTask(file: File, signal?: AbortSignal) { const formData = new FormData() formData.append('file', file) - return http.upload<{ code: number, data: any, msg: string }>('/api/trademark/newTask', formData) + return http.upload<{ code: number, data: any, msg: string }>('/api/trademark/newTask', formData, signal) }, // 获取任务列表及筛选数据(调用 erp_client_sb) - getTask() { - return http.post<{ - code: number, - data: { - original: any, + getTask(signal?: AbortSignal) { + return http.post<{ + code: number, + data: { + original: any, filtered: Record[], // 完整的行数据(Map格式) headers: string[] // 表头 - }, - msg: string - }>('/api/trademark/task') + }, + msg: string + }>('/api/trademark/task', undefined, signal) }, // 品牌商标筛查 - brandCheck(brands: string[], taskId?: string) { - return http.post<{ code: number, data: { total: number, checked: number, registered: number, unregistered: number, failed: number, data: any[], duration: string }, msg: string }>('/api/trademark/brandCheck', { brands, taskId }) + brandCheck(brands: string[], taskId?: string, signal?: AbortSignal) { + return http.post<{ code: number, data: { total: number, checked: number, registered: number, unregistered: number, failed: number, data: any[], duration: string }, msg: string }>('/api/trademark/brandCheck', { brands, taskId }, signal) }, // 查询品牌筛查进度 diff --git a/electron-vue-template/src/renderer/components/amazon/AmazonDashboard.vue b/electron-vue-template/src/renderer/components/amazon/AmazonDashboard.vue index 40e988f..12ce93e 100644 --- a/electron-vue-template/src/renderer/components/amazon/AmazonDashboard.vue +++ b/electron-vue-template/src/renderer/components/amazon/AmazonDashboard.vue @@ -107,10 +107,28 @@ function handleCancelTask() { } } +const isRetrying = ref(false) +let lastRetryTime = 0 + function handleRetryTask() { + const now = Date.now() + if (now - lastRetryTime < 3000 || isRetrying.value || loading.value || trademarkPanelRef.value?.trademarkLoading) { + return + } + + lastRetryTime = now + isRetrying.value = true + if (trademarkPanelRef.value && typeof trademarkPanelRef.value.startTrademarkQuery === 'function') { trademarkPanelRef.value.startTrademarkQuery() } + + const checkInterval = setInterval(() => { + if (trademarkPanelRef.value?.trademarkLoading || Date.now() - now > 2000) { + clearInterval(checkInterval) + isRetrying.value = false + } + }, 50) } function openSubscribeDialog() { @@ -176,19 +194,6 @@ function handleExportData() {
- -
-
-
-
-
-
-
-
{{ progressPercentage }}%
-
-
-
-
@@ -276,15 +281,14 @@ function handleExportData() {
-
@@ -429,11 +433,11 @@ function handleExportData() {
未注册 - {{ trademarkPanelRef?.isBrandTaskRealData ? trademarkPanelRef.taskProgress.brand.completed : '-' }} + {{ trademarkPanelRef?.brandStatsDisplay?.unregistered || '-' }}
已注册 - {{ trademarkPanelRef?.isBrandTaskRealData ? (trademarkPanelRef.taskProgress.brand.total - trademarkPanelRef.taskProgress.brand.completed) : '-' }} + {{ trademarkPanelRef?.brandStatsDisplay?.registered || '-' }}
@@ -702,13 +706,6 @@ function handleExportData() { .text:focus { border-color: #409EFF; } .text:disabled { background: #f5f7fa; color: #c0c4cc; } .action-buttons { display: flex; gap: 10px; flex-wrap: wrap; } -.progress-section { margin: 0px 12px 0px 12px; } -.progress-head { margin-bottom: 8px; } -.progress-box { padding: 4px 0; } -.progress-container { display: flex; align-items: center; gap: 8px; } -.progress-bar { flex: 1; height: 6px; background: #e3eeff; border-radius: 999px; overflow: hidden; } -.progress-fill { height: 100%; background: #1677FF; border-radius: 999px; transition: width 0.3s ease; } -.progress-text { font-size: 13px; color: #1677FF; font-weight: 500; min-width: 44px; text-align: right; } .current-status { font-size: 12px; color: #606266; padding-left: 2px; } .table-container { display: flex; @@ -970,6 +967,7 @@ function handleExportData() { width: 48px; height: 48px; } + .done-banner .banner-icon { background: transparent; } diff --git a/electron-vue-template/src/renderer/components/amazon/AsinQueryPanel.vue b/electron-vue-template/src/renderer/components/amazon/AsinQueryPanel.vue index afcff14..37891a4 100644 --- a/electron-vue-template/src/renderer/components/amazon/AsinQueryPanel.vue +++ b/electron-vue-template/src/renderer/components/amazon/AsinQueryPanel.vue @@ -365,7 +365,7 @@ defineExpose({ .step-header { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; } .title { font-size: 14px; font-weight: 600; color: #303133; text-align: left; } .desc { font-size: 12px; color: #909399; margin-bottom: 10px; text-align: left; line-height: 1.5; } -.links { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; } +.links { display: flex; align-items: center; gap: 2px; margin-bottom: 8px; } .link { color: #409EFF; cursor: pointer; font-size: 12px; } .sep { color: #dcdfe6; } .dropzone { border: 1px dashed #c0c4cc; border-radius: 6px; padding: 16px; text-align: center; cursor: pointer; background: #fafafa; } diff --git a/electron-vue-template/src/renderer/components/amazon/TrademarkCheckPanel.vue b/electron-vue-template/src/renderer/components/amazon/TrademarkCheckPanel.vue index bff7e75..3cc1831 100644 --- a/electron-vue-template/src/renderer/components/amazon/TrademarkCheckPanel.vue +++ b/electron-vue-template/src/renderer/components/amazon/TrademarkCheckPanel.vue @@ -1,10 +1,11 @@ @@ -742,25 +927,28 @@ defineExpose({
1
-
导入Excel表格
+
+
导入Excel表格
+
在卖家精灵导出文档时,必须要勾选“导出主图”。导入的表格必须具备“品牌”,“商品主图”两个表头,商品主图必须为超链接。 - 点击查看示例
-
点击查看示例
+
📤
{{ uploadLoading ? '正在验证表头...' : '点击或将文件拖拽到这里上传' }}
支持 .xls .xlsx
- - + +
{{ trademarkFileName }} @@ -768,43 +956,47 @@ defineExpose({
- +
2
-
选择亚马逊商家账号
+
+
选择亚马逊商家账号
+
请确保账号地区与专利地区一致,不一致可能导致结果不准确或失败。
- +
- avatar + avatar {{ acc.name || acc.username }} ✔️
- +
添加账号 账号管理
- +
2
-
选择产品品牌地区
+
+
选择产品品牌地区
+
暂时仅支持美国品牌商标筛查,后续将开放更多地区,敬请期待。
@@ -813,14 +1005,19 @@ defineExpose({
- +
3
-
选择需查询的(可多选)
-
默认查询违规产品,可多选
- +
+
选择需查询的(可多选)
+
+
商标筛查包含以下维度,后续将开放更 + 多维度的筛查条件与自定义条件组合功 + 能,敬请期待 +
+
@@ -831,7 +1028,7 @@ defineExpose({
筛查未注册商标或TM标的商品
- +
@@ -841,7 +1038,7 @@ defineExpose({
筛查未注册商标的品牌
- +
@@ -855,60 +1052,123 @@ defineExpose({
- +
{{ completedSteps }}/{{ totalConfigSteps }} - + 开始筛查 - - 停止筛查 -
- - + + - Excel格式示例 + Excel格式示例