![]()
setTimeout(resolve, pollInterval))
- if (!trademarkLoading.value) return
-
- // 尝试获取任务结果
- try {
- taskResult = await markApi.getTask()
-
- if (taskResult.code === 200 || taskResult.code === 0) {
- // 检查是否有 download_url,有则说明任务完成
- if (taskResult.data.original?.download_url) {
- break
- }
- }
- } catch (err) {
- // 继续等待
- console.log('等待任务处理中...', err)
+ // 启动进度动画(5-95%)
+ const progressTimer = setInterval(() => {
+ if (taskData.current < 95) {
+ taskData.current = Math.min(taskData.current + 3, 95)
}
- }
+ }, 500)
- if (!trademarkLoading.value) return
-
- // 步骤3: 检查是否成功获取到结果
- if (!taskResult || (taskResult.code !== 200 && taskResult.code !== 0)) {
- throw new Error('获取任务超时或失败,请重试')
- }
-
- if (!taskResult.data.original?.download_url) {
- throw new Error('任务处理超时,请稍后重试')
- }
-
- productResult = taskResult
-
- // 从后端获取真实的统计数据
- taskData.total = taskResult.data.original?.total || 0
- taskData.completed = taskResult.data.filtered.length
- taskData.current = taskData.total
-
- // 映射后端数据到前端格式
- trademarkData.value = taskResult.data.filtered.map((item: any) => ({
- name: item['品牌'] || '',
- status: item['商标类型'] || '',
- class: '',
- owner: '',
- expireDate: item['注册时间'] || '',
- similarity: 0,
- // 保留原始数据供后续使用
- asin: item['ASIN'],
- productImage: item['商品主图']
- }))
-
- // 如果需要品牌筛查,从产品结果中提取品牌列表
- if (needBrandCheck) {
- brandList = taskResult.data.filtered
- .map((item: any) => item['品牌'])
- .filter((brand: string) => brand && brand.trim())
- }
-
- showMessage(`产品筛查完成,共查询 ${taskData.total} 条,筛查出 ${taskData.completed} 条未注册/TM标`, 'success')
- }
-
- // 品牌商标筛查
- if (needBrandCheck) {
- if (!trademarkLoading.value) return
-
- // 如果没有执行产品筛查,需要先上传文件获取品牌列表
- if (!needProductCheck) {
- showMessage('正在上传文件提取品牌列表...', 'info')
-
- // 调用新建任务接口获取处理后的数据
- const createResult = await markApi.newTask(trademarkFile.value)
-
- if (createResult.code !== 200 && createResult.code !== 0) {
- throw new Error(createResult.msg || '创建任务失败')
- }
-
- // 轮询获取任务结果
+ // 轮询检查任务状态
+ const pollTask = async () => {
const maxWaitTime = 60000
const pollInterval = 3000
const startTime = Date.now()
let taskResult: any = null
while (Date.now() - startTime < maxWaitTime) {
- if (!trademarkLoading.value) return
+ if (!trademarkLoading.value) {
+ clearInterval(progressTimer)
+ return null
+ }
await new Promise(resolve => setTimeout(resolve, pollInterval))
- if (!trademarkLoading.value) return
+ if (!trademarkLoading.value) {
+ clearInterval(progressTimer)
+ return null
+ }
try {
taskResult = await markApi.getTask()
-
if (taskResult.code === 200 || taskResult.code === 0) {
if (taskResult.data.original?.download_url) {
- break
+ clearInterval(progressTimer)
+ return taskResult
}
}
} catch (err) {
- console.log('等待任务处理中...', err)
+ // 继续等待
}
}
+ clearInterval(progressTimer)
+ return taskResult
+ }
+
+ try {
+ productResult = await pollTask()
if (!trademarkLoading.value) return
- if (!taskResult || (taskResult.code !== 200 && taskResult.code !== 0)) {
+ if (!productResult || (productResult.code !== 200 && productResult.code !== 0)) {
throw new Error('获取任务超时或失败,请重试')
}
- if (!taskResult.data.original?.download_url) {
+ if (!productResult.data.original?.download_url) {
throw new Error('任务处理超时,请稍后重试')
}
- // 从结果中提取品牌列表(包括TM和未注册的品牌)
- brandList = taskResult.data.filtered
+ // 设置真实统计数据
+ taskData.total = productResult.data.original?.total || 0
+ taskData.current = taskData.total
+ taskData.completed = productResult.data.filtered.length
+ } finally {
+ clearInterval(progressTimer)
+ }
+
+ // 映射后端数据到前端格式
+ trademarkData.value = productResult.data.filtered.map((item: any) => ({
+ name: item['品牌'] || '',
+ status: item['商标类型'] || '',
+ class: '',
+ owner: '',
+ expireDate: item['注册时间'] || '',
+ similarity: 0,
+ asin: item['ASIN'],
+ productImage: item['商品主图']
+ }))
+
+ // 如果需要品牌筛查,从产品结果中提取品牌列表
+ if (needBrandCheck) {
+ brandList = productResult.data.filtered
.map((item: any) => item['品牌'])
.filter((brand: string) => brand && brand.trim())
+ }
+
+ showMessage(`产品筛查完成,共 ${taskData.total} 条,筛查出 ${taskData.completed} 条`, 'success')
+ }
+
+ // 品牌商标筛查
+ if (needBrandCheck) {
+ if (!trademarkLoading.value) return
+
+ // 如果没有执行产品筛查,需要先从Excel提取品牌列表
+ if (!needProductCheck) {
+ showMessage('正在从Excel提取品牌列表...', 'info')
+ const extractResult = await markApi.extractBrands(trademarkFile.value)
+ if (extractResult.code !== 200 && extractResult.code !== 0) {
+ throw new Error(extractResult.msg || '提取品牌列表失败')
+ }
+
+ if (!extractResult.data.brands || extractResult.data.brands.length === 0) {
+ throw new Error('未能从文件中提取到品牌数据,请确保Excel包含"品牌"列')
+ }
+
+ brandList = extractResult.data.brands
showMessage(`品牌列表提取成功,共 ${brandList.length} 个品牌`, 'success')
}
@@ -308,15 +288,13 @@ async function startTrademarkQuery() {
showMessage(`开始品牌商标筛查,共 ${brandList.length} 个品牌...`, 'info')
- // 模拟进度动画(每秒增加20个)
- const batchSize = 20
+ // 模拟进度动画
brandProgressTimer = setInterval(() => {
if (brandData.current < brandList.length * 0.95) {
- brandData.current = Math.min(brandData.current + batchSize, brandList.length * 0.95)
+ brandData.current = Math.min(brandData.current + 20, brandList.length * 0.95)
}
}, 1000)
- // 调用品牌筛查接口(浏览器内并发,速度快)
const brandResult = await markApi.brandCheck(brandList)
if (brandProgressTimer) clearInterval(brandProgressTimer)
@@ -352,29 +330,37 @@ async function startTrademarkQuery() {
emit('updateData', trademarkData.value)
let summaryMsg = '筛查完成'
- if (needProductCheck) {
- const taskData = taskProgress.value.product
- summaryMsg += `,产品:${taskData.completed}/${taskData.total}`
- }
- if (needBrandCheck && brandList.length > 0) {
- const brandData = taskProgress.value.brand
- summaryMsg += `,品牌:${brandData.completed}/${brandData.total}`
- }
+ if (needProductCheck) summaryMsg += `,产品:${taskProgress.value.product.completed}/${taskProgress.value.product.total}`
+ if (needBrandCheck && brandList.length > 0) summaryMsg += `,品牌:${taskProgress.value.brand.completed}/${taskProgress.value.brand.total}`
showMessage(summaryMsg, 'success')
}
} catch (error: any) {
- if (error.message && error.message.includes('网络')) {
+ const hasProductData = taskProgress.value.product.total > 0
+
+ // 优化错误信息 - 只显示友好提示
+ let msg = error.message || ''
+ if (msg.includes('网络') || msg.includes('network')) {
queryStatus.value = 'networkError'
- errorMessage.value = '网络连接失败'
+ errorMessage.value = '网络不可用,请检查你的网络或代理设置'
+ } else if (msg.includes('超时') || msg.includes('timeout')) {
+ queryStatus.value = 'error'
+ errorMessage.value = '数据库维护中,请稍后重试'
+ } else if (msg.includes('403') || msg.includes('风控')) {
+ queryStatus.value = 'error'
+ errorMessage.value = '网站风控限制,请稍后重试'
} else {
queryStatus.value = 'error'
- errorMessage.value = error.message || '查询失败'
+ errorMessage.value = '数据库维护中,请稍后重试'
+ }
+
+ // 仅在第1步失败时清空数据
+ if (!hasProductData) {
+ trademarkData.value = []
+ emit('updateData', [])
+ } else {
+ emit('updateData', trademarkData.value)
}
showMessage(errorMessage.value, 'error')
-
- // 失败时清空数据,不显示侧边栏
- trademarkData.value = []
- emit('updateData', [])
} finally {
// 清除定时器
if (brandProgressTimer) {
@@ -466,10 +452,13 @@ function resetToIdle() {
trademarkData.value = []
trademarkFileName.value = ''
trademarkFile.value = null
+ taskProgress.value.product.total = 0
taskProgress.value.product.current = 0
taskProgress.value.product.completed = 0
+ taskProgress.value.brand.total = 0
taskProgress.value.brand.current = 0
taskProgress.value.brand.completed = 0
+ taskProgress.value.platform.total = 0
taskProgress.value.platform.current = 0
taskProgress.value.platform.completed = 0
}
@@ -481,8 +470,10 @@ defineExpose({
queryStatus,
statusConfig,
taskProgress,
+ errorMessage,
resetToIdle,
- stopTrademarkQuery
+ stopTrademarkQuery,
+ startTrademarkQuery
})
@@ -493,8 +484,8 @@ defineExpose({
1
-
-
在卖家精灵导出文档时,必须要勾选“导出主图”,具体操作请点击查看
+
+
产品筛查:需导入卖家精灵选品表格,并勾选"导出主图";品牌筛查:Excel需包含"品牌"列
📤
点击或将文件拖拽到这里上传
@@ -798,6 +789,12 @@ defineExpose({
font-weight: 500;
border-radius: 6px;
}
+.start-btn:disabled {
+ background: #d9d9d9;
+ border-color: #d9d9d9;
+ color: #ffffff;
+ cursor: not-allowed;
+}
.stop-btn {
background: #f56c6c;
border-color: #f56c6c;
diff --git a/erp_client_sb/src/main/java/com/tashow/erp/controller/TrademarkController.java b/erp_client_sb/src/main/java/com/tashow/erp/controller/TrademarkController.java
index 3660c1f..ae1b4bd 100644
--- a/erp_client_sb/src/main/java/com/tashow/erp/controller/TrademarkController.java
+++ b/erp_client_sb/src/main/java/com/tashow/erp/controller/TrademarkController.java
@@ -1,19 +1,20 @@
package com.tashow.erp.controller;
+import com.tashow.erp.utils.ExcelParseUtil;
import com.tashow.erp.utils.JsonData;
import com.tashow.erp.utils.LoggerUtil;
import com.tashow.erp.utils.TrademarkCheckUtil;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
import java.util.*;
-import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
-
/**
* 商标检查控制器 - 极速版(浏览器内并发)
*/
@RestController
@RequestMapping("/api/trademark")
+@CrossOrigin
public class TrademarkController {
private static final Logger logger = LoggerUtil.getLogger(TrademarkController.class);
@@ -31,10 +32,7 @@ public class TrademarkController {
.map(String::trim)
.distinct()
.collect(Collectors.toList());
-
- logger.info("开始检查 {}个品牌", list.size());
long start = System.currentTimeMillis();
-
// 串行查询(不加延迟)
List