紫鸟查询店铺更新

This commit is contained in:
super
2026-04-02 01:15:50 +08:00
parent 63043c56d4
commit 1fdef3c67f
17 changed files with 891 additions and 51 deletions

View File

@@ -105,7 +105,7 @@
<div class="left split-result-main">
<span class="id" :title="item.sourceFilename">{{ item.sourceFilename || '-' }}</span>
<div class="files">店铺名{{ item.shopName || '-' }}</div>
<div class="files">匹配结果{{ item.matched ? `已匹配 ${item.shopId || ''}` : '未匹配到紫鸟店铺' }}</div>
<div class="files">匹配结果{{ formatMatchResult(item) }}</div>
<div v-if="item.platform" class="files">平台{{ item.platform }}</div>
<div v-if="getQueueStatus(item)" class="files">队列状态{{ getQueueStatus(item) }}</div>
<div v-if="item.countryCount !== undefined && item.matched" class="files">国家数{{ item.countryCount
@@ -158,7 +158,7 @@
<div class="left split-result-main">
<span class="id" :title="item.sourceFilename">{{ item.sourceFilename || '-' }}</span>
<div class="files">店铺名{{ item.shopName || '-' }}</div>
<div class="files">匹配结果{{ item.matched ? `已匹配 ${item.shopId || ''}` : '未匹配到紫鸟店铺' }}</div>
<div class="files">匹配结果{{ formatMatchResult(item) }}</div>
<div v-if="item.platform" class="files">平台{{ item.platform }}</div>
<div v-if="item.countryCount !== undefined && item.matched" class="files">国家数{{ item.countryCount
}}</div>
@@ -281,8 +281,7 @@ function loadSessionTasksFromStorage() {
}
function saveSessionTask(taskId: number, items: DeleteBrandResultItem[], pushResult?: string, payloadText?: string) {
// 只将解析成功且匹配成功的任务放入当前队列中,失败的将留在历史记录里
const validItems = items.filter(i => i.matched !== false && i.success !== false)
const validItems = items.filter(i => i.matchStatus === 'MATCHED' && i.success !== false)
if (validItems.length === 0) return
const newTask: StoredCurrentTask = {
@@ -326,6 +325,9 @@ function getTaskStatus(taskId?: number) {
function getDisplayError(item: DeleteBrandResultItem) {
if (item.error) return item.error
if (item.matchStatus && item.matchStatus !== 'MATCHED') {
return item.matchMessage || ''
}
const taskId = item.taskId
if (!taskId) return ''
return taskDetails.value[taskId]?.task?.errorMessage || ''
@@ -339,18 +341,37 @@ function shouldShowProgress(item: DeleteBrandResultItem) {
function normalizeDeleteBrandItems(items: DeleteBrandResultItem[]) {
return items.map((item) => {
// 只有在既没成功,又显式标记为未匹配时,才做错误兜底
if (!item.success && item.matched === false) {
return {
...item,
error: item.error || '未匹配到紫鸟店铺',
openStoreUrl: undefined,
}
if (item.matchStatus === 'MATCHED') {
return item
}
return {
...item,
matched: false,
openStoreUrl: undefined,
error: item.error || undefined,
}
return item
})
}
function formatMatchResult(item: DeleteBrandResultItem) {
if (item.matchStatus === 'MATCHED') {
return `已匹配 ${item.shopId || ''}`.trim()
}
if (item.matchMessage) {
return item.matchMessage
}
if (item.matchStatus === 'CONFLICT') {
return '存在多个同名店铺,请人工确认'
}
if (item.matchStatus === 'PENDING' || item.matchStatus === 'INDEX_STALE') {
return '店铺索引暂未就绪'
}
if (item.matchStatus) {
return item.matchStatus
}
return item.matched ? `已匹配 ${item.shopId || ''}`.trim() : '待匹配'
}
function mergeVisibleItems() {
resultItems.value = [...currentSectionItems.value, ...historySectionItems.value]
}
@@ -369,10 +390,6 @@ function updateSummary(items: DeleteBrandResultItem[]) {
}
}
function getItemTaskId(item: DeleteBrandResultItem) {
return item.taskId || 0
}
function formatProgress(taskId: number) {
if (!taskId) return ''
const detail = taskDetails.value[taskId]
@@ -410,11 +427,6 @@ function formatProgressPercent(taskId: number) {
return status === 'SUCCESS' ? 100 : 0
}
function isTaskRunning(taskId: number) {
const status = taskDetails.value[taskId]?.task?.status
return status === 'RUNNING'
}
function isTaskTerminal(taskId: number) {
const status = taskDetails.value[taskId]?.task?.status
return status === 'SUCCESS' || status === 'FAILED'
@@ -477,18 +489,58 @@ function canDownloadTaskResult(item: DeleteBrandResultItem) {
return status === 'SUCCESS'
}
function mergeTaskDetailItemsIntoSession(detail: DeleteBrandTaskDetailVo) {
const taskId = detail?.task?.id
if (!taskId || !detail?.items?.length) return false
const sessionTask = sessionTasks.value.find(t => t.taskId === taskId)
if (!sessionTask) return false
let changed = false
const mergedItems = sessionTask.items.map((item) => {
const latest = detail.items?.find((candidate) => candidate.resultId === item.resultId || candidate.sourceFilename === item.sourceFilename)
if (!latest) return item
const merged = {
...item,
...latest,
success: item.success ?? latest.success,
}
if (JSON.stringify(merged) !== JSON.stringify(item)) {
changed = true
}
return merged
})
const validItems = mergedItems.filter(i => i.matchStatus === 'MATCHED' && i.success !== false)
if (JSON.stringify(validItems) !== JSON.stringify(sessionTask.items)) {
sessionTask.items = validItems
changed = true
}
if (changed && typeof window !== 'undefined') {
window.localStorage.setItem(getStorageKey(), JSON.stringify(sessionTasks.value))
}
return changed
}
async function refreshTaskDetails(taskIds?: number[]) {
const ids = taskIds || getPollingTaskIds()
if (!ids.length) return
try {
const batch = await getDeleteBrandTaskDetails(ids)
let changed = false
for (const detail of batch.items || []) {
const id = detail?.task?.id
if (typeof id === 'number' && id > 0) {
taskDetails.value[id] = detail
if (mergeTaskDetailItemsIntoSession(detail)) {
changed = true
}
}
}
if (changed) {
syncResultState()
}
} catch {
// ignore polling failures
}
@@ -649,7 +701,8 @@ async function submitRun() {
})),
})
const normalizedItems = normalizeDeleteBrandItems(result.items || [])
const hasUnmatched = normalizedItems.some((item) => !item.matched)
const hasMatchedItems = normalizedItems.some((item) => item.matchStatus === 'MATCHED')
const hasPendingItems = normalizedItems.some((item) => item.matchStatus && item.matchStatus !== 'MATCHED')
queuePushResult.value = '解析完成,等待手动点击打开紫鸟进行单任务处理'
queuePayloadText.value = ''
@@ -659,10 +712,12 @@ async function submitRun() {
}
syncResultState()
if (hasUnmatched) {
ElMessage.error('存在未匹配到紫鸟店铺的文件,请检查报错内容。这些文件已自动归档至历史记录。')
} else {
if (hasPendingItems) {
ElMessage.warning('部分文件尚未命中可用店铺索引,已保留状态信息,请等待后台刷新后重试。')
} else if (hasMatchedItems) {
ElMessage.success('删除品牌解析完成,请手动推送')
} else {
ElMessage.warning('当前没有可推送的已匹配文件,请先等待店铺索引刷新。')
}
// 更新历史记录,以展示那些未进入队列的失败项
@@ -783,10 +838,7 @@ function findNextAutoRunnableItem() {
}
async function runItem(item: DeleteBrandResultItem, options?: { auto?: boolean }) {
if (isPythonQueueBusy()) {
if (!options?.auto) {
ElMessage.warning('当前存在正在处理的任务,请等待其完成后再推送下一条!')
}
if (options?.auto && isPythonQueueBusy()) {
return false
}
@@ -816,7 +868,7 @@ async function runItem(item: DeleteBrandResultItem, options?: { auto?: boolean }
const pushResult = await api.enqueue_json(payload)
let qpr = ''
if (pushResult?.success) {
qpr = `单独推送文件 ${item.sourceFilename},当前队列长度:${pushResult.queue_size ?? '-'}`
qpr = `已推送文件 ${item.sourceFilename},当前队列长度:${pushResult.queue_size ?? '-'}`
const sessionItem = sessionTask.items.find(i => i.resultId === item.resultId || i.sourceFilename === item.sourceFilename)
if (sessionItem) {
@@ -874,10 +926,6 @@ async function triggerItemRun(item: DeleteBrandResultItem) {
}
}
function openShop(url: string) {
window.open(url, '_blank')
}
onMounted(() => {
loadSessionTasksFromStorage()
const taskIds = getPollingTaskIds()

View File

@@ -211,12 +211,16 @@ export interface DeleteBrandTaskBatchVo {
missingTaskIds: number[]
}
export type DeleteBrandMatchStatus = 'MATCHED' | 'PENDING' | 'CONFLICT' | 'INDEX_STALE'
export interface DeleteBrandResultItem {
resultId?: number
fileKey?: string
sourceFilename: string
shopName?: string
matched?: boolean
matchStatus?: DeleteBrandMatchStatus
matchMessage?: string
shopId?: string
platform?: string
openStoreUrl?: string