异常记录检测修改
This commit is contained in:
@@ -215,6 +215,7 @@ import { expandBrandFolderRecursive, type BrandExpandFolderItem } from '@/shared
|
||||
import {
|
||||
deleteDeleteBrandHistory,
|
||||
getDeleteBrandHistory,
|
||||
getDeleteBrandResultDownloadUrl,
|
||||
getDeleteBrandTaskDetails,
|
||||
getDeleteBrandTaskProgress,
|
||||
getDeleteBrandTaskDownloadUrl,
|
||||
@@ -269,8 +270,9 @@ const timers = createCategorizedTimers('delete-brand')
|
||||
const displayPaths = computed(() => selectedPaths.value.slice(0, 10))
|
||||
|
||||
const currentSectionItems = computed(() => {
|
||||
const sortedTasks = [...sessionTasks.value].sort((left, right) => (right.createdAt || 0) - (left.createdAt || 0))
|
||||
const allCurrent: DeleteBrandResultItem[] = [];
|
||||
sessionTasks.value.forEach(task => {
|
||||
sortedTasks.forEach(task => {
|
||||
allCurrent.push(...task.items);
|
||||
});
|
||||
return allCurrent;
|
||||
@@ -521,9 +523,10 @@ function shouldShowProgress(item: DeleteBrandResultItem) {
|
||||
|
||||
function normalizeDeleteBrandItems(items: DeleteBrandResultItem[]) {
|
||||
return items.map((item) => {
|
||||
if (item.matched || item.matchStatus === 'MATCHED' || item.matchStatus === 'INDEX_STALE') {
|
||||
if (isUsableMatchedItem(item)) {
|
||||
return {
|
||||
...item,
|
||||
matched: true,
|
||||
_pushed: false,
|
||||
_completed: false,
|
||||
} as SessionDeleteBrandItem
|
||||
@@ -540,10 +543,10 @@ function normalizeDeleteBrandItems(items: DeleteBrandResultItem[]) {
|
||||
}
|
||||
|
||||
function formatMatchResult(item: DeleteBrandResultItem) {
|
||||
if (item.matched && item.matchStatus === 'INDEX_STALE') {
|
||||
return item.matchMessage || `已匹配 ${item.shopId || ''}(索引过期)`.trim()
|
||||
if (item.matchStatus === 'INDEX_STALE' && isUsableMatchedItem(item)) {
|
||||
return `已匹配 ${item.shopId || ''}(索引过期,可继续推送)`.trim()
|
||||
}
|
||||
if (item.matchStatus === 'MATCHED') {
|
||||
if (item.matchStatus === 'MATCHED' || item.matched) {
|
||||
return `已匹配 ${item.shopId || ''}`.trim()
|
||||
}
|
||||
if (item.matchMessage) {
|
||||
@@ -749,6 +752,12 @@ function getQueueStatus(item: DeleteBrandResultItem) {
|
||||
return '已被全局判定为终态'
|
||||
}
|
||||
|
||||
// 后端已经把单文件结果组装出来时,以文件终态为准。
|
||||
// 多店铺同 taskId 场景下任务本身仍是 RUNNING,不能因此挡住下一个店铺入队。
|
||||
if (isFileResultReady(item) || isFileResultReady(sessionItem)) {
|
||||
return '本文件解析完毕'
|
||||
}
|
||||
|
||||
// 先看前端会话态:一旦该文件已判定完成,优先展示完成,避免被 RUNNING 覆盖导致链式推进卡住。
|
||||
if (sessionItem?._completed) {
|
||||
return '本文件解析完毕'
|
||||
@@ -791,6 +800,21 @@ function canDownloadTaskResult(item: DeleteBrandResultItem) {
|
||||
return false
|
||||
}
|
||||
|
||||
function isFileResultReady(item?: Partial<DeleteBrandResultItem> | null) {
|
||||
if (!item) return false
|
||||
const fileStatus = String(item.fileStatus || '').toUpperCase()
|
||||
return Boolean(
|
||||
item.fileReady
|
||||
|| item.downloadUrl
|
||||
|| fileStatus === 'SUCCESS'
|
||||
|| fileStatus === 'COMPLETED',
|
||||
)
|
||||
}
|
||||
|
||||
function preferLatestValue<T>(latestValue: T | null | undefined, currentValue: T | null | undefined) {
|
||||
return latestValue ?? currentValue
|
||||
}
|
||||
|
||||
function mergeTaskDetailItemsIntoSession(detail: DeleteBrandTaskDetailVo) {
|
||||
const taskId = detail?.task?.id
|
||||
if (!taskId) return false
|
||||
@@ -821,10 +845,21 @@ function mergeTaskDetailItemsIntoSession(detail: DeleteBrandTaskDetailVo) {
|
||||
const merged = {
|
||||
...item,
|
||||
...latest,
|
||||
// progress/batch 返回的是轻量文件状态,店铺匹配信息和执行 payload 可能为空;
|
||||
// 不能覆盖本地解析出的完整店铺数据,否则后续文件会失去入队资格。
|
||||
shopName: preferLatestValue(latest.shopName, item.shopName),
|
||||
companyName: preferLatestValue(latest.companyName, item.companyName),
|
||||
shopId: preferLatestValue(latest.shopId, item.shopId),
|
||||
platform: preferLatestValue(latest.platform, item.platform),
|
||||
openStoreUrl: preferLatestValue(latest.openStoreUrl, item.openStoreUrl),
|
||||
matchStatus: preferLatestValue(latest.matchStatus, item.matchStatus),
|
||||
matchMessage: preferLatestValue(latest.matchMessage, item.matchMessage),
|
||||
matched: isUsableMatchedItem(item) || isUsableMatchedItem(latest),
|
||||
countryCount: preferLatestValue(latest.countryCount, item.countryCount),
|
||||
countries,
|
||||
previewRows,
|
||||
_pushed: item._pushed,
|
||||
_completed: item._completed,
|
||||
_completed: item._completed || isFileResultReady(latest),
|
||||
} as SessionDeleteBrandItem
|
||||
if (JSON.stringify(merged) !== JSON.stringify(item)) {
|
||||
changed = true
|
||||
@@ -837,7 +872,7 @@ function mergeTaskDetailItemsIntoSession(detail: DeleteBrandTaskDetailVo) {
|
||||
mergedItems.push({
|
||||
...latest,
|
||||
_pushed: false,
|
||||
_completed: false,
|
||||
_completed: isFileResultReady(latest),
|
||||
} as SessionDeleteBrandItem)
|
||||
changed = true
|
||||
}
|
||||
@@ -956,6 +991,8 @@ function ensurePolling(immediate = false) {
|
||||
}
|
||||
|
||||
function getTaskStatusInfo(item: DeleteBrandResultItem) {
|
||||
if (item.fileReady || item.downloadUrl) return { className: 'success', text: '已完成' }
|
||||
|
||||
// 1. 优先查实时详情中的状态
|
||||
const status = item.taskId ? taskDetails.value[item.taskId]?.task?.status : null
|
||||
if (status === 'SUCCESS') return { className: 'success', text: '已完成' }
|
||||
@@ -1053,13 +1090,9 @@ async function submitRun() {
|
||||
})),
|
||||
})
|
||||
const normalizedItems = normalizeDeleteBrandItems(result.items || [])
|
||||
const hasRunnableItems = normalizedItems.some((item) =>
|
||||
item.matchStatus === 'MATCHED' || item.matchStatus === 'INDEX_STALE' || item.matched
|
||||
)
|
||||
const hasRunnableItems = normalizedItems.some((item) => isUsableMatchedItem(item))
|
||||
const hasStaleMatchedItems = normalizedItems.some((item) => item.matchStatus === 'INDEX_STALE' && item.matched)
|
||||
const hasBlockedItems = normalizedItems.some((item) =>
|
||||
!item.matched && item.matchStatus !== 'MATCHED' && item.matchStatus !== 'INDEX_STALE'
|
||||
)
|
||||
const hasBlockedItems = normalizedItems.some((item) => !isUsableMatchedItem(item))
|
||||
|
||||
queuePushResult.value = hasRunnableItems
|
||||
? '解析完成,可在左侧点击“推送到 Python 队列”开始串行处理'
|
||||
@@ -1097,7 +1130,7 @@ async function downloadTaskResult(item: DeleteBrandResultItem) {
|
||||
return
|
||||
}
|
||||
const api = getPywebviewApi()
|
||||
const url = getDeleteBrandTaskDownloadUrl(taskId)
|
||||
const url = item.resultId ? getDeleteBrandResultDownloadUrl(item.resultId) : getDeleteBrandTaskDownloadUrl(taskId)
|
||||
const filename =
|
||||
item.outputFilename ||
|
||||
item.sourceFilename ||
|
||||
@@ -1219,8 +1252,24 @@ function getItemKey(item: DeleteBrandResultItem) {
|
||||
return `task:${item.taskId || 0}:${item.sourceFilename || ''}`
|
||||
}
|
||||
|
||||
function isUsableMatchedItem(item: DeleteBrandResultItem) {
|
||||
return Boolean(
|
||||
item.matched
|
||||
|| item.matchStatus === 'MATCHED'
|
||||
|| (item.matchStatus === 'INDEX_STALE' && item.shopId),
|
||||
)
|
||||
}
|
||||
|
||||
function hasRunnableDeleteBrandPayload(item: DeleteBrandResultItem) {
|
||||
return Boolean(
|
||||
item.shopName
|
||||
&& Array.isArray(item.countries)
|
||||
&& item.countries.length > 0,
|
||||
)
|
||||
}
|
||||
|
||||
function canPushToQueue(item: DeleteBrandResultItem) {
|
||||
return Boolean(item.taskId && (item.matchStatus === 'MATCHED' || item.matchStatus === 'INDEX_STALE' || item.matched))
|
||||
return Boolean(item.taskId && (isUsableMatchedItem(item) || hasRunnableDeleteBrandPayload(item)))
|
||||
}
|
||||
|
||||
function findNextAutoRunnableItem() {
|
||||
|
||||
Reference in New Issue
Block a user