style(frontend): 全站背景图 webp 化(bg.jpg 4MB→251KB 压缩 + bg.webp)+品牌工具页默认策略调优(品牌检测默认改精确匹配 Simple、Terms 后置)+任务面板/登录页/亚马逊控制台观感微调
This commit is contained in:
@@ -143,7 +143,7 @@
|
||||
</div>
|
||||
|
||||
<div v-if="queuePushResult" class="queue-debug-card">
|
||||
<div class="section-title queue-debug-title">推送结果</div>
|
||||
<div class="section-title queue-debug-title">启动结果</div>
|
||||
<div class="queue-debug-line">{{ queuePushResult }}</div>
|
||||
<pre v-if="queuePayloadText" class="queue-debug-payload">{{ queuePayloadText }}</pre>
|
||||
</div>
|
||||
@@ -163,7 +163,7 @@
|
||||
>
|
||||
<template #cards-extra>
|
||||
<div class="subsection-title">匹配结果</div>
|
||||
<div v-if="!matchedItems.length" class="match-empty">完成「匹配店铺」后,在此展示紫鸟索引匹配结果,供核对后再推送队列。</div>
|
||||
<div v-if="!matchedItems.length" class="match-empty">完成「匹配店铺」后,在此展示匹配结果,确认无误后再启动任务。</div>
|
||||
<el-table v-else :data="matchedItems" :row-key="rowKeyForMatch" :highlight-current-row="false"
|
||||
class="result-table match-table">
|
||||
<el-table-column prop="shopName" label="店铺名" min-width="100" />
|
||||
@@ -812,16 +812,16 @@ async function runMatch() {
|
||||
|
||||
function formatMatchStatus(status: string | undefined) {
|
||||
const s = (status || '').trim()
|
||||
const map: Record<string, string> = { MATCHED: '已匹配', PENDING: '待匹配', CONFLICT: '需人工确认', INDEX_STALE: '索引过期' }
|
||||
const map: Record<string, string> = { MATCHED: '已匹配', PENDING: '待匹配', CONFLICT: '需人工确认', INDEX_STALE: '匹配已过期' }
|
||||
return map[s] || (s ? s : '—')
|
||||
}
|
||||
|
||||
function formatMatchRemark(row: PriceTrackShopQueueItem) {
|
||||
const msg = (row.matchMessage || '').trim()
|
||||
if (msg) return msg
|
||||
if (row.matched && row.matchStatus === 'MATCHED') return '紫鸟索引已命中,可推送队列'
|
||||
if (row.matched) return '已关联索引,请结合状态列查看是否可推送'
|
||||
return '未命中或未就绪,请检查店铺名与索引刷新'
|
||||
if (row.matched && row.matchStatus === 'MATCHED') return '已匹配成功,可启动任务'
|
||||
if (row.matched) return '已关联店铺,请查看状态确认'
|
||||
return '未匹配成功,请检查店铺名'
|
||||
}
|
||||
|
||||
function rowKeyForMatch(row: { shopName?: string; shopId?: number | string | null }) {
|
||||
@@ -934,7 +934,7 @@ async function removeMatchedRow(row: PriceTrackShopQueueItem) {
|
||||
await loadHistory()
|
||||
await loadDashboard()
|
||||
syncPollingIdsWithHistory()
|
||||
ElMessage.success('后端记录已不存在,已同步移除本地记录')
|
||||
ElMessage.success('记录已不存在,已同步移除本地记录')
|
||||
return
|
||||
}
|
||||
matchedItems.value = backup
|
||||
@@ -1027,7 +1027,7 @@ async function waitForTaskTerminal(taskId: number) {
|
||||
try {
|
||||
const batch = await getPriceTrackTaskProgressBatch([taskId])
|
||||
if (transientErrorCount > 0) {
|
||||
queuePushResult.value = `任务 ${taskId} 后端已恢复,继续等待执行结果...`
|
||||
queuePushResult.value = `任务 ${taskId} 服务已恢复,继续等待执行结果...`
|
||||
}
|
||||
transientErrorCount = 0
|
||||
if ((batch.missingTaskIds || []).includes(taskId)) {
|
||||
@@ -1057,15 +1057,15 @@ async function waitForTaskTerminal(taskId: number) {
|
||||
}
|
||||
} catch (error) {
|
||||
const message = (error instanceof Error ? error.message : String(error || '')).toLowerCase()
|
||||
const transient = ['无法连接到后端服务', 'bad gateway', 'gateway timeout', 'network error', 'timeout', '502', '503', '504'].some((pattern) => message.includes(pattern.toLowerCase()))
|
||||
const transient = ['无法连接到服务', 'bad gateway', 'gateway timeout', 'network error', 'timeout', '502', '503', '504'].some((pattern) => message.includes(pattern.toLowerCase()))
|
||||
if (!transient) throw error
|
||||
transientErrorCount += 1
|
||||
if (transientErrorCount >= maxTransientErrors) {
|
||||
throw new Error(`任务 ${taskId} 等待后端恢复超时,请稍后手动刷新查看状态`)
|
||||
throw new Error(`任务 ${taskId} 等待服务恢复超时,请稍后手动刷新查看状态`)
|
||||
}
|
||||
queuePushResult.value = `任务 ${taskId} 运行中,正在等待后端服务恢复(${transientErrorCount}/${maxTransientErrors})...`
|
||||
queuePushResult.value = `任务 ${taskId} 运行中,正在等待服务恢复(${transientErrorCount}/${maxTransientErrors})...`
|
||||
if (transientErrorCount === 1 || transientErrorCount % 5 === 0) {
|
||||
ElMessage.warning(`任务 ${taskId} 运行中,后端服务暂时不可用,正在自动重试`)
|
||||
ElMessage.warning(`任务 ${taskId} 运行中,服务暂时不可用,正在自动重试`)
|
||||
}
|
||||
await sleep(getPollIntervalMs())
|
||||
continue
|
||||
@@ -1130,10 +1130,10 @@ async function processMatchedQueue() {
|
||||
})
|
||||
} catch (error) {
|
||||
const message = (error instanceof Error ? error.message : String(error || '')).toLowerCase()
|
||||
const transient = ['无法连接到后端服务', 'bad gateway', 'gateway timeout', 'network error', 'timeout', '502', '503', '504'].some((pattern) => message.includes(pattern.toLowerCase()))
|
||||
const transient = ['无法连接到服务', 'bad gateway', 'gateway timeout', 'network error', 'timeout', '502', '503', '504'].some((pattern) => message.includes(pattern.toLowerCase()))
|
||||
attempt += 1
|
||||
if (!transient || attempt >= 10) throw error
|
||||
queuePushResult.value = '后端服务暂时不可用,正在重试创建任务(' + attempt + '/10)...'
|
||||
queuePushResult.value = '服务暂时不可用,正在重试创建任务(' + attempt + '/10)...'
|
||||
await sleep(getPollIntervalMs())
|
||||
}
|
||||
}
|
||||
@@ -1157,7 +1157,7 @@ async function processMatchedQueue() {
|
||||
addPollingTask(taskVo.taskId)
|
||||
scheduleNextPoll(true)
|
||||
removeMatchedRowsLocally([row])
|
||||
queuePushResult.value = '任务 ' + taskVo.taskId + ' 已入队,等待执行完成'
|
||||
queuePushResult.value = '任务 ' + taskVo.taskId + ' 已提交,等待执行完成'
|
||||
const finalStatus = await waitForTaskTerminal(taskVo.taskId)
|
||||
if (finalStatus !== 'SUCCESS') {
|
||||
failedCount += 1
|
||||
@@ -1177,11 +1177,11 @@ async function processMatchedQueue() {
|
||||
}
|
||||
}
|
||||
if (successCount > 0 || failedCount > 0) {
|
||||
ElMessage.success('店铺任务推送已完成:成功 ' + successCount + ' 条,失败 ' + failedCount + ' 条')
|
||||
ElMessage.success('店铺任务启动已完成:成功 ' + successCount + ' 条,失败 ' + failedCount + ' 条')
|
||||
}
|
||||
} catch (e) {
|
||||
if (disposed) return
|
||||
queuePushResult.value = e instanceof Error ? e.message : '推送异常'
|
||||
queuePushResult.value = e instanceof Error ? e.message : '启动异常'
|
||||
ElMessage.error(queuePushResult.value)
|
||||
} finally {
|
||||
queueWorkerRunning.value = false
|
||||
@@ -1214,7 +1214,7 @@ async function syncActiveLoopRun() {
|
||||
return activeLoopRun.value
|
||||
} catch (error) {
|
||||
const message = (error instanceof Error ? error.message : String(error || '')).toLowerCase()
|
||||
const transient = ['无法连接到后端服务', 'bad gateway', 'gateway timeout', 'network error', 'timeout', '502', '503', '504'].some((pattern) => message.includes(pattern.toLowerCase()))
|
||||
const transient = ['无法连接到服务', 'bad gateway', 'gateway timeout', 'network error', 'timeout', '502', '503', '504'].some((pattern) => message.includes(pattern.toLowerCase()))
|
||||
if (transient) return activeLoopRun.value
|
||||
activeLoopRun.value = null
|
||||
activeLoopRunId.value = null
|
||||
@@ -1285,10 +1285,10 @@ async function runLoopExecution(loopId?: number) {
|
||||
return await completePriceTrackLoopChild(loop.id, activeTaskId)
|
||||
} catch (error) {
|
||||
const message = (error instanceof Error ? error.message : String(error || '')).toLowerCase()
|
||||
const transient = ['无法连接到后端服务', 'bad gateway', 'gateway timeout', 'network error', 'timeout', '502', '503', '504'].some((pattern) => message.includes(pattern.toLowerCase()))
|
||||
const transient = ['无法连接到服务', 'bad gateway', 'gateway timeout', 'network error', 'timeout', '502', '503', '504'].some((pattern) => message.includes(pattern.toLowerCase()))
|
||||
completeAttempt += 1
|
||||
if (!transient || completeAttempt >= 10) throw error
|
||||
queuePushResult.value = `循环任务 ${loop.id} 等待后端恢复后确认子任务完成(${completeAttempt}/10)...`
|
||||
queuePushResult.value = `循环任务 ${loop.id} 等待服务恢复后确认子任务完成(${completeAttempt}/10)...`
|
||||
await sleep(getPollIntervalMs())
|
||||
}
|
||||
}
|
||||
@@ -1312,10 +1312,10 @@ async function runLoopExecution(loopId?: number) {
|
||||
return await dispatchNextPriceTrackLoopRun(loop.id)
|
||||
} catch (error) {
|
||||
const message = (error instanceof Error ? error.message : String(error || '')).toLowerCase()
|
||||
const transient = ['无法连接到后端服务', 'bad gateway', 'gateway timeout', 'network error', 'timeout', '502', '503', '504'].some((pattern) => message.includes(pattern.toLowerCase()))
|
||||
const transient = ['无法连接到服务', 'bad gateway', 'gateway timeout', 'network error', 'timeout', '502', '503', '504'].some((pattern) => message.includes(pattern.toLowerCase()))
|
||||
dispatchAttempt += 1
|
||||
if (!transient || dispatchAttempt >= 10) throw error
|
||||
queuePushResult.value = `循环任务 ${loop.id} 等待后端恢复后继续派发(${dispatchAttempt}/10)...`
|
||||
queuePushResult.value = `循环任务 ${loop.id} 等待服务恢复后继续执行(${dispatchAttempt}/10)...`
|
||||
await sleep(getPollIntervalMs())
|
||||
}
|
||||
}
|
||||
@@ -1336,10 +1336,10 @@ async function runLoopExecution(loopId?: number) {
|
||||
return await createPriceTrackTask(childTaskRequest)
|
||||
} catch (error) {
|
||||
const message = (error instanceof Error ? error.message : String(error || '')).toLowerCase()
|
||||
const transient = ['无法连接到后端服务', 'bad gateway', 'gateway timeout', 'network error', 'timeout', '502', '503', '504'].some((pattern) => message.includes(pattern.toLowerCase()))
|
||||
const transient = ['无法连接到服务', 'bad gateway', 'gateway timeout', 'network error', 'timeout', '502', '503', '504'].some((pattern) => message.includes(pattern.toLowerCase()))
|
||||
createAttempt += 1
|
||||
if (!transient || createAttempt >= 10) throw error
|
||||
queuePushResult.value = `循环任务 ${loop.id} 等待后端恢复后重试创建子任务(${createAttempt}/10)...`
|
||||
queuePushResult.value = `循环任务 ${loop.id} 等待服务恢复后重试创建子任务(${createAttempt}/10)...`
|
||||
await sleep(getPollIntervalMs())
|
||||
}
|
||||
}
|
||||
@@ -1351,7 +1351,7 @@ async function runLoopExecution(loopId?: number) {
|
||||
addPollingTask(taskVo.taskId)
|
||||
scheduleNextPoll(true)
|
||||
removeMatchedRowsLocally([row])
|
||||
queuePushResult.value = `循环任务 ${loop.id} 第 ${dispatch.childTaskRequest.roundIndex || 1} 轮已推送:${row.shopName || taskVo.taskId}`
|
||||
queuePushResult.value = `循环任务 ${loop.id} 第 ${dispatch.childTaskRequest.roundIndex || 1} 轮已启动:${row.shopName || taskVo.taskId}`
|
||||
}
|
||||
} finally {
|
||||
loopDispatching.value = false
|
||||
@@ -1637,7 +1637,7 @@ async function deleteTaskRecord(item: PriceTrackHistoryItem) {
|
||||
removeHistoryItemLocally(item)
|
||||
await loadDashboard()
|
||||
syncPollingIdsWithHistory()
|
||||
ElMessage.success('后端记录已不存在,已同步移除本地记录')
|
||||
ElMessage.success('记录已不存在,已同步移除本地记录')
|
||||
return
|
||||
}
|
||||
ElMessage.error(e instanceof Error ? e.message : '删除失败')
|
||||
@@ -1707,7 +1707,7 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
<style scoped>
|
||||
.module-page {
|
||||
min-height: 100vh;
|
||||
background: #151a25;
|
||||
background: #242424;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
@@ -1718,7 +1718,7 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
|
||||
.left-panel {
|
||||
width: 400px;
|
||||
background: #1c2333;
|
||||
background: #242424;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid #2e3a52;
|
||||
@@ -1733,7 +1733,7 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
background: #151a25;
|
||||
background: #242424;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
@@ -1746,7 +1746,7 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
border: 1px dashed #3e4a62;
|
||||
border-radius: 10px;
|
||||
padding: 16px;
|
||||
background: #2e3a52;
|
||||
background: #242424;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@@ -1798,7 +1798,7 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
border: 1px dashed #3e4a62;
|
||||
border-radius: 10px;
|
||||
padding: 14px 16px;
|
||||
background: #2e3a52;
|
||||
background: #242424;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -1845,7 +1845,7 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
}
|
||||
|
||||
.loop-round-input :deep(.el-input__wrapper) {
|
||||
background-color: #2e3a52;
|
||||
background-color: #242424;
|
||||
box-shadow: 0 0 0 1px #3e4a62 inset;
|
||||
}
|
||||
|
||||
@@ -1893,7 +1893,7 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
border: 1px dashed #3e4a62;
|
||||
border-radius: 10px;
|
||||
padding: 16px;
|
||||
background: #2e3a52;
|
||||
background: #242424;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@@ -1911,7 +1911,7 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
padding: 8px 14px;
|
||||
font-size: 13px;
|
||||
color: #c8d2e2;
|
||||
background: #2e3a52;
|
||||
background: #242424;
|
||||
border: 1px solid #3e4a62;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
@@ -1965,7 +1965,7 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
border: 1px solid #333;
|
||||
border-radius: 8px;
|
||||
padding: 10px 12px;
|
||||
background: #2e3a52;
|
||||
background: #242424;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
@@ -2028,7 +2028,7 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
}
|
||||
|
||||
.listing-filter-row :deep(.el-select__wrapper) {
|
||||
background-color: #2e3a52;
|
||||
background-color: #242424;
|
||||
box-shadow: 0 0 0 1px #3e4a62 inset;
|
||||
}
|
||||
|
||||
@@ -2062,8 +2062,8 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
}
|
||||
|
||||
.candidate-table {
|
||||
--el-table-bg-color: #2e3a52;
|
||||
--el-table-tr-bg-color: #2e3a52;
|
||||
--el-table-bg-color: #242424;
|
||||
--el-table-tr-bg-color: #242424;
|
||||
--el-table-header-bg-color: #2e3a52;
|
||||
--el-table-text-color: #c8d2e2;
|
||||
--el-table-border-color: #333;
|
||||
@@ -2205,8 +2205,8 @@ async function batchDeleteHistory(views: TaskItemView[]) {
|
||||
}
|
||||
|
||||
.result-table {
|
||||
--el-table-bg-color: #222;
|
||||
--el-table-tr-bg-color: #222;
|
||||
--el-table-bg-color: #242424;
|
||||
--el-table-tr-bg-color: #242424;
|
||||
--el-table-header-bg-color: #2e3a52;
|
||||
--el-table-text-color: #c8d2e2;
|
||||
--el-table-border-color: #333;
|
||||
|
||||
Reference in New Issue
Block a user