feat(trademark): 支持商标筛查任务取消状态及优化错误处理- 新增商标筛查取消状态的UI展示和处理逻辑
-优化错误提示信息,区分网络错误、超时和风控场景 - 改进任务进度计算逻辑,支持更准确的完成状态判断 - 调整品牌提取逻辑,从Excel中直接读取品牌列数据 - 增强后端403错误检测和代理自动切换机制 - 更新前端组件样式和交互逻辑以匹配新状态 -修复部分条件判断逻辑以提升稳定性- 调整文件上传大小限制至50MB以支持更大文件- 优化Excel解析工具类,支持自动识别表头行位置
This commit is contained in:
@@ -16,6 +16,13 @@ export const markApi = {
|
||||
// 品牌商标筛查
|
||||
brandCheck(brands: string[]) {
|
||||
return http.post<{ code: number, data: { total: number, filtered: number, passed: number, data: any[] }, msg: string }>('/tool/mark/brandCheck', brands)
|
||||
},
|
||||
|
||||
// 从Excel提取品牌列表(客户端本地接口)
|
||||
extractBrands(file: File) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return http.upload<{ code: number, data: { total: number, brands: string[] }, msg: string }>('/api/trademark/extractBrands', formData)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ function handleRetryTask() {
|
||||
|
||||
<div class="body-layout">
|
||||
<!-- 左侧步骤栏 (商标筛查有数据时隐藏) -->
|
||||
<aside v-show="!(currentTab === 'trademark' && (trademarkPanelRef?.queryStatus === 'inProgress' || trademarkPanelRef?.queryStatus === 'done' || trademarkPanelRef?.queryStatus === 'error' || trademarkPanelRef?.queryStatus === 'networkError'))" :class="['steps-sidebar', currentTab === 'trademark' ? 'wide' : 'narrow']">
|
||||
<aside v-show="!(currentTab === 'trademark' && (trademarkPanelRef?.queryStatus === 'inProgress' || trademarkPanelRef?.queryStatus === 'done' || trademarkPanelRef?.queryStatus === 'error' || trademarkPanelRef?.queryStatus === 'networkError' || trademarkPanelRef?.queryStatus === 'cancel'))" :class="['steps-sidebar', currentTab === 'trademark' ? 'wide' : 'narrow']">
|
||||
<div class="steps-title">操作流程:</div>
|
||||
|
||||
<!-- ASIN查询面板 -->
|
||||
@@ -176,7 +176,7 @@ function handleRetryTask() {
|
||||
</div>
|
||||
|
||||
<!-- ASIN查询表格 -->
|
||||
<table v-if="currentTab === 'asin'" class="table">
|
||||
<table v-if="currentTab === 'asin'" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ASIN</th>
|
||||
@@ -200,8 +200,8 @@ function handleRetryTask() {
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- 商标筛查进度显示 -->
|
||||
<div v-if="currentTab === 'trademark' && (trademarkPanelRef?.queryStatus === 'inProgress' || trademarkPanelRef?.queryStatus === 'done' || trademarkPanelRef?.queryStatus === 'error' || trademarkPanelRef?.queryStatus === 'networkError')" class="trademark-progress-container">
|
||||
<!-- 商标筛查进度显示 -->
|
||||
<div v-if="currentTab === 'trademark' && (trademarkPanelRef?.queryStatus === 'inProgress' || trademarkPanelRef?.queryStatus === 'done' || trademarkPanelRef?.queryStatus === 'error' || trademarkPanelRef?.queryStatus === 'networkError' || trademarkPanelRef?.queryStatus === 'cancel')" class="trademark-progress-container">
|
||||
<!-- 进行中状态横幅 -->
|
||||
<div v-if="trademarkPanelRef?.queryStatus === 'inProgress'" class="status-banner progress-banner">
|
||||
<div class="banner-icon">
|
||||
@@ -216,18 +216,34 @@ function handleRetryTask() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 完成/失败状态横幅(样式统一) -->
|
||||
<div v-if="trademarkPanelRef?.queryStatus === 'done' || trademarkPanelRef?.queryStatus === 'error' || trademarkPanelRef?.queryStatus === 'networkError'" class="status-banner done-banner">
|
||||
<!-- 取消状态横幅 -->
|
||||
<div v-if="trademarkPanelRef?.queryStatus === 'cancel'" class="status-banner cancel-banner">
|
||||
<div class="banner-icon">
|
||||
<img src="/icon/done1.png" alt="完成" class="icon-image" />
|
||||
<img src="/icon/cancel.png" alt="已取消" class="icon-image" />
|
||||
</div>
|
||||
<div class="banner-content">
|
||||
<div class="banner-title">筛查已完成</div>
|
||||
<div class="banner-desc">点击"导出数据"按钮,可导出为 Excel 表格文件。如出现异常,请检查账号地区设置。</div>
|
||||
<div class="banner-title">已取消查询</div>
|
||||
<div class="banner-desc">您已取消本次查询任务</div>
|
||||
</div>
|
||||
<div class="banner-actions">
|
||||
<el-button size="default" @click="handleNewTask">新建任务</el-button>
|
||||
<el-button type="primary" size="default">导出数据</el-button>
|
||||
<el-button type="primary" size="default" @click="handleRetryTask">重新筛查</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 完成/失败状态横幅 -->
|
||||
<div v-if="trademarkPanelRef?.queryStatus === 'done' || trademarkPanelRef?.queryStatus === 'error' || trademarkPanelRef?.queryStatus === 'networkError'" class="status-banner done-banner">
|
||||
<div class="banner-icon">
|
||||
<img :src="trademarkPanelRef.queryStatus === 'done' ? '/icon/done1.png' : '/icon/error.png'" alt="完成" class="icon-image" />
|
||||
</div>
|
||||
<div class="banner-content">
|
||||
<div class="banner-title">{{ trademarkPanelRef.queryStatus === 'done' ? '筛查已完成' : '数据筛查失败' }}</div>
|
||||
<div class="banner-desc">{{ trademarkPanelRef.queryStatus === 'done' ? '点击"导出数据"按钮,可导出为 Excel 表格文件。' : (trademarkPanelRef.errorMessage || '请稍后重试') }}</div>
|
||||
</div>
|
||||
<div class="banner-actions">
|
||||
<el-button size="default" @click="handleNewTask">新建任务</el-button>
|
||||
<el-button v-if="trademarkPanelRef.queryStatus === 'done'" type="primary" size="default">导出数据</el-button>
|
||||
<el-button v-else type="primary" size="default" @click="handleRetryTask">重新筛查</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -240,22 +256,27 @@ function handleRetryTask() {
|
||||
<div class="status-column">
|
||||
<!-- 任务1:产品商标筛查 -->
|
||||
<div class="status-item">
|
||||
<img v-if="trademarkPanelRef?.queryStatus === 'error' || trademarkPanelRef?.queryStatus === 'networkError'" src="/icon/error.png" alt="筛查失败" class="status-indicator-icon" />
|
||||
<img v-else-if="(trademarkPanelRef?.taskProgress?.product?.current || 0) >= (trademarkPanelRef?.taskProgress?.product?.total || 1) && (trademarkPanelRef?.taskProgress?.product?.total || 0) > 0" src="/icon/done.png" alt="采集完成" class="status-indicator-icon" />
|
||||
<img v-else-if="trademarkPanelRef?.queryStatus === 'inProgress'" src="/icon/inProgress.png" alt="采集中" class="status-indicator-icon" />
|
||||
<img v-if="(trademarkPanelRef?.taskProgress?.product?.total || 0) > 100" src="/icon/done.png" alt="采集完成" class="status-indicator-icon" />
|
||||
<img v-else-if="((trademarkPanelRef?.taskProgress?.product?.total || 0) > 0 || (trademarkPanelRef?.taskProgress?.product?.current || 0) > 0) && (trademarkPanelRef?.queryStatus === 'error' || trademarkPanelRef?.queryStatus === 'networkError')" src="/icon/error.png" alt="筛查失败" class="status-indicator-icon" />
|
||||
<img v-else-if="((trademarkPanelRef?.taskProgress?.product?.total || 0) > 0 || (trademarkPanelRef?.taskProgress?.product?.current || 0) > 0) && trademarkPanelRef?.queryStatus === 'cancel'" src="/icon/cancel.png" alt="已取消" class="status-indicator-icon" />
|
||||
<img v-else-if="(trademarkPanelRef?.taskProgress?.product?.current || 0) > 0" src="/icon/inProgress.png" alt="采集中" class="status-indicator-icon" />
|
||||
<img v-else src="/icon/acquisition.png" alt="待采集" class="status-indicator-icon" />
|
||||
</div>
|
||||
<div class="status-connector"></div>
|
||||
<!-- 任务2:品牌商标筛查 -->
|
||||
<div class="status-item">
|
||||
<img v-if="(trademarkPanelRef?.taskProgress?.brand?.current || 0) >= (trademarkPanelRef?.taskProgress?.brand?.total || 1)" src="/icon/done.png" alt="采集完成" class="status-indicator-icon" />
|
||||
<img v-if="(trademarkPanelRef?.taskProgress?.brand?.total || 0) > 0 && (trademarkPanelRef?.taskProgress?.brand?.current || 0) >= trademarkPanelRef.taskProgress.brand.total" src="/icon/done.png" alt="采集完成" class="status-indicator-icon" />
|
||||
<img v-else-if="((trademarkPanelRef?.taskProgress?.brand?.total || 0) > 0 || (trademarkPanelRef?.taskProgress?.brand?.current || 0) > 0) && (trademarkPanelRef?.queryStatus === 'error' || trademarkPanelRef?.queryStatus === 'networkError')" src="/icon/error.png" alt="筛查失败" class="status-indicator-icon" />
|
||||
<img v-else-if="((trademarkPanelRef?.taskProgress?.brand?.total || 0) > 0 || (trademarkPanelRef?.taskProgress?.brand?.current || 0) > 0) && trademarkPanelRef?.queryStatus === 'cancel'" src="/icon/cancel.png" alt="已取消" class="status-indicator-icon" />
|
||||
<img v-else-if="(trademarkPanelRef?.taskProgress?.brand?.current || 0) > 0" src="/icon/inProgress.png" alt="采集中" class="status-indicator-icon" />
|
||||
<img v-else src="/icon/acquisition.png" alt="待采集" class="status-indicator-icon" />
|
||||
</div>
|
||||
<div class="status-connector"></div>
|
||||
<!-- 任务3:跟卖许可筛查 -->
|
||||
<div class="status-item">
|
||||
<img v-if="(trademarkPanelRef?.taskProgress?.platform?.current || 0) >= (trademarkPanelRef?.taskProgress?.platform?.total || 1)" src="/icon/done.png" alt="采集完成" class="status-indicator-icon" />
|
||||
<img v-if="(trademarkPanelRef?.taskProgress?.platform?.total || 0) > 0 && (trademarkPanelRef?.taskProgress?.platform?.current || 0) >= trademarkPanelRef.taskProgress.platform.total" src="/icon/done.png" alt="采集完成" class="status-indicator-icon" />
|
||||
<img v-else-if="((trademarkPanelRef?.taskProgress?.platform?.total || 0) > 0 || (trademarkPanelRef?.taskProgress?.platform?.current || 0) > 0) && (trademarkPanelRef?.queryStatus === 'error' || trademarkPanelRef?.queryStatus === 'networkError')" src="/icon/error.png" alt="筛查失败" class="status-indicator-icon" />
|
||||
<img v-else-if="((trademarkPanelRef?.taskProgress?.platform?.total || 0) > 0 || (trademarkPanelRef?.taskProgress?.platform?.current || 0) > 0) && trademarkPanelRef?.queryStatus === 'cancel'" src="/icon/cancel.png" alt="已取消" class="status-indicator-icon" />
|
||||
<img v-else-if="(trademarkPanelRef?.taskProgress?.platform?.current || 0) > 0" src="/icon/inProgress.png" alt="采集中" class="status-indicator-icon" />
|
||||
<img v-else src="/icon/acquisition.png" alt="待采集" class="status-indicator-icon" />
|
||||
</div>
|
||||
@@ -267,7 +288,7 @@ function handleRetryTask() {
|
||||
<div class="task-title-row">
|
||||
<div class="task-info">
|
||||
<div class="task-name">{{ trademarkPanelRef?.taskProgress?.product?.label || '未注册/TM商标筛查' }}</div>
|
||||
<div class="task-desc">{{ trademarkPanelRef?.taskProgress?.product?.desc || '筛查未注册商标或TM标的产品' }}<span v-if="trademarkPanelRef?.queryStatus !== 'inProgress'"> (已完成)</span></div>
|
||||
<div class="task-desc">{{ trademarkPanelRef?.taskProgress?.product?.desc || '筛查未注册商标或TM标的产品' }}<span v-if="(trademarkPanelRef?.taskProgress?.product?.total || 0) > 0"> (已完成)</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="task-progress-wrapper">
|
||||
@@ -279,15 +300,15 @@ function handleRetryTask() {
|
||||
<div class="task-stats">
|
||||
<div class="task-stat">
|
||||
<span class="stat-label">查询数量</span>
|
||||
<span class="stat-value">{{ (trademarkPanelRef?.taskProgress?.product?.total || 0) === 0 ? '-' : trademarkPanelRef.taskProgress.product.total }}</span>
|
||||
<span class="stat-value">{{ (trademarkPanelRef?.taskProgress?.product?.total || 0) > 100 ? trademarkPanelRef.taskProgress.product.total : '-' }}</span>
|
||||
</div>
|
||||
<div class="task-stat highlight">
|
||||
<span class="stat-label">未注册/TM标</span>
|
||||
<span class="stat-value">{{ (trademarkPanelRef?.taskProgress?.product?.total || 0) > 0 ? (trademarkPanelRef?.taskProgress?.product?.completed || 0) : '-' }}</span>
|
||||
<span class="stat-value">{{ (trademarkPanelRef?.taskProgress?.product?.total || 0) > 100 ? (trademarkPanelRef?.taskProgress?.product?.completed || 0) : '-' }}</span>
|
||||
</div>
|
||||
<div class="task-stat">
|
||||
<span class="stat-label">已过滤</span>
|
||||
<span class="stat-value">{{ (trademarkPanelRef?.taskProgress?.product?.total || 0) > 0 ? ((trademarkPanelRef?.taskProgress?.product?.total || 0) - (trademarkPanelRef?.taskProgress?.product?.completed || 0)) : '-' }}</span>
|
||||
<span class="stat-value">{{ (trademarkPanelRef?.taskProgress?.product?.total || 0) > 100 ? ((trademarkPanelRef?.taskProgress?.product?.total || 0) - (trademarkPanelRef?.taskProgress?.product?.completed || 0)) : '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -296,7 +317,7 @@ function handleRetryTask() {
|
||||
<div class="task-title-row">
|
||||
<div class="task-info">
|
||||
<div class="task-name">{{ trademarkPanelRef?.taskProgress?.brand?.label || '品牌商标筛查' }}</div>
|
||||
<div class="task-desc">{{ trademarkPanelRef?.taskProgress?.brand?.desc || '筛查未注册商标的品牌' }}<span v-if="trademarkPanelRef?.queryStatus !== 'inProgress'"> (已完成)</span></div>
|
||||
<div class="task-desc">{{ trademarkPanelRef?.taskProgress?.brand?.desc || '筛查未注册商标的品牌' }}<span v-if="(trademarkPanelRef?.taskProgress?.brand?.total || 0) > 0 && (trademarkPanelRef?.taskProgress?.brand?.current || 0) >= trademarkPanelRef.taskProgress.brand.total"> (已完成)</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="task-progress-wrapper">
|
||||
@@ -312,11 +333,11 @@ function handleRetryTask() {
|
||||
</div>
|
||||
<div class="task-stat highlight">
|
||||
<span class="stat-label">未注册</span>
|
||||
<span class="stat-value">{{ (trademarkPanelRef?.taskProgress?.brand?.total || 0) > 0 ? (trademarkPanelRef?.taskProgress?.brand?.completed || 0) : '-' }}</span>
|
||||
<span class="stat-value">{{ ((trademarkPanelRef?.taskProgress?.brand?.current || 0) >= (trademarkPanelRef?.taskProgress?.brand?.total || 1)) ? (trademarkPanelRef?.taskProgress?.brand?.completed || 0) : '-' }}</span>
|
||||
</div>
|
||||
<div class="task-stat">
|
||||
<span class="stat-label">已注册</span>
|
||||
<span class="stat-value">{{ (trademarkPanelRef?.taskProgress?.brand?.total || 0) > 0 ? ((trademarkPanelRef?.taskProgress?.brand?.total || 0) - (trademarkPanelRef?.taskProgress?.brand?.completed || 0)) : '-' }}</span>
|
||||
<span class="stat-value">{{ ((trademarkPanelRef?.taskProgress?.brand?.current || 0) >= (trademarkPanelRef?.taskProgress?.brand?.total || 1)) ? ((trademarkPanelRef?.taskProgress?.brand?.total || 0) - (trademarkPanelRef?.taskProgress?.brand?.completed || 0)) : '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -342,11 +363,11 @@ function handleRetryTask() {
|
||||
</div>
|
||||
<div class="task-stat highlight">
|
||||
<span class="stat-label">可跟卖</span>
|
||||
<span class="stat-value">{{ (trademarkPanelRef?.taskProgress?.platform?.total || 0) > 0 ? (trademarkPanelRef?.taskProgress?.platform?.completed || 0) : '-' }}</span>
|
||||
<span class="stat-value">{{ ((trademarkPanelRef?.taskProgress?.platform?.current || 0) >= (trademarkPanelRef?.taskProgress?.platform?.total || 1)) ? (trademarkPanelRef?.taskProgress?.platform?.completed || 0) : '-' }}</span>
|
||||
</div>
|
||||
<div class="task-stat">
|
||||
<span class="stat-label">已过滤</span>
|
||||
<span class="stat-value">{{ (trademarkPanelRef?.taskProgress?.platform?.total || 0) > 0 ? ((trademarkPanelRef?.taskProgress?.platform?.total || 0) - (trademarkPanelRef?.taskProgress?.platform?.completed || 0)) : '-' }}</span>
|
||||
<span class="stat-value">{{ ((trademarkPanelRef?.taskProgress?.platform?.current || 0) >= (trademarkPanelRef?.taskProgress?.platform?.total || 1)) ? ((trademarkPanelRef?.taskProgress?.platform?.total || 0) - (trademarkPanelRef?.taskProgress?.platform?.completed || 0)) : '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -355,9 +376,9 @@ function handleRetryTask() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="paginatedData.length === 0 && !(currentTab === 'trademark' && (trademarkPanelRef?.queryStatus === 'inProgress' || trademarkPanelRef?.queryStatus === 'done' || trademarkPanelRef?.queryStatus === 'error' || trademarkPanelRef?.queryStatus === 'networkError'))" class="empty-abs">
|
||||
<div v-if="paginatedData.length === 0 && !(currentTab === 'trademark' && (trademarkPanelRef?.queryStatus === 'inProgress' || trademarkPanelRef?.queryStatus === 'done' || trademarkPanelRef?.queryStatus === 'error' || trademarkPanelRef?.queryStatus === 'networkError' || trademarkPanelRef?.queryStatus === 'cancel'))" class="empty-abs">
|
||||
<!-- 商标筛查状态显示 -->
|
||||
<div v-if="currentTab === 'trademark' && trademarkPanelRef?.queryStatus && trademarkPanelRef.queryStatus !== 'inProgress' && trademarkPanelRef.queryStatus !== 'done' && trademarkPanelRef.queryStatus !== 'error' && trademarkPanelRef.queryStatus !== 'networkError'" class="empty-container">
|
||||
<div v-if="currentTab === 'trademark' && trademarkPanelRef?.queryStatus && trademarkPanelRef.queryStatus !== 'inProgress' && trademarkPanelRef.queryStatus !== 'done' && trademarkPanelRef.queryStatus !== 'error' && trademarkPanelRef.queryStatus !== 'networkError' && trademarkPanelRef.queryStatus !== 'cancel'" class="empty-container">
|
||||
<img
|
||||
:src="trademarkPanelRef.statusConfig[trademarkPanelRef.queryStatus].icon"
|
||||
:alt="trademarkPanelRef.statusConfig[trademarkPanelRef.queryStatus].title"
|
||||
@@ -787,15 +808,12 @@ function handleRetryTask() {
|
||||
flex: none;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.status-banner.progress-banner {
|
||||
.status-banner.progress-banner,
|
||||
.status-banner.done-banner,
|
||||
.status-banner.error-banner,
|
||||
.status-banner.cancel-banner {
|
||||
box-shadow: 0px 8px 20px rgba(22, 119, 255, 0.2);
|
||||
}
|
||||
.status-banner.done-banner {
|
||||
box-shadow: 0px 8px 20px rgba(103, 194, 58, 0.2);
|
||||
}
|
||||
.status-banner.error-banner {
|
||||
box-shadow: 0px 8px 20px rgba(245, 108, 108, 0.2);
|
||||
}
|
||||
.banner-icon {
|
||||
flex-shrink: 0;
|
||||
width: 64px;
|
||||
@@ -878,7 +896,7 @@ function handleRetryTask() {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
.status-indicator-icon[src*="inProgress"] {
|
||||
animation: spin 1.5s linear infinite;
|
||||
}
|
||||
|
||||
@@ -131,12 +131,15 @@ async function startTrademarkQuery() {
|
||||
return
|
||||
}
|
||||
|
||||
const needProductCheck = queryTypes.value.includes('product')
|
||||
const needBrandCheck = queryTypes.value.includes('brand')
|
||||
|
||||
trademarkLoading.value = true
|
||||
trademarkProgress.value = 0
|
||||
trademarkData.value = []
|
||||
queryStatus.value = 'inProgress'
|
||||
|
||||
// 完全重置任务进度(包括total)
|
||||
// 重置任务进度
|
||||
taskProgress.value.product.total = 0
|
||||
taskProgress.value.product.current = 0
|
||||
taskProgress.value.product.completed = 0
|
||||
@@ -154,10 +157,6 @@ async function startTrademarkQuery() {
|
||||
let productResult: any = null
|
||||
let brandList: string[] = []
|
||||
|
||||
// 判断是否需要执行产品商标筛查
|
||||
const needProductCheck = queryTypes.value.includes('product')
|
||||
const needBrandCheck = queryTypes.value.includes('brand')
|
||||
|
||||
if (needProductCheck) {
|
||||
// 步骤1: 产品商标筛查 - 调用新建任务接口
|
||||
showMessage('正在上传文件...', 'info')
|
||||
@@ -169,132 +168,113 @@ async function startTrademarkQuery() {
|
||||
|
||||
showMessage('文件上传成功,正在处理...', 'success')
|
||||
|
||||
// 步骤2: 轮询检查任务状态,最多等待60秒
|
||||
const taskData = taskProgress.value.product
|
||||
const maxWaitTime = 60000 // 最多等60秒
|
||||
const pollInterval = 3000 // 每3秒检查一次
|
||||
const startTime = Date.now()
|
||||
taskData.total = 100 // 设置临时总数以显示进度动画
|
||||
taskData.current = 5 // 立即显示初始进度
|
||||
|
||||
let taskResult: any = null
|
||||
while (Date.now() - startTime < maxWaitTime) {
|
||||
if (!trademarkLoading.value) return
|
||||
|
||||
// 等待一段时间
|
||||
await new Promise(resolve => 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
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -493,8 +484,8 @@ defineExpose({
|
||||
<div class="flow-item">
|
||||
<div class="step-index">1</div>
|
||||
<div class="step-card">
|
||||
<div class="step-header"><div class="title">导入“卖家精灵选品表格”</div></div>
|
||||
<div class="desc">在卖家精灵导出文档时,必须要勾选“导出主图”,具体操作请<span class="link" @click.prevent="viewTrademarkExample">点击查看</span></div>
|
||||
<div class="step-header"><div class="title">导入Excel表格</div></div>
|
||||
<div class="desc">产品筛查:需导入卖家精灵选品表格,并勾选"导出主图";品牌筛查:Excel需包含"品牌"列</div>
|
||||
<div class="dropzone" @click="openTrademarkUpload">
|
||||
<div class="dz-icon">📤</div>
|
||||
<div class="dz-text">点击或将文件拖拽到这里上传</div>
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user