完成后端架构重构等
This commit is contained in:
@@ -312,6 +312,8 @@ const matchedItems = ref<PriceTrackShopQueueItem[]>([])
|
||||
const adding = ref(false)
|
||||
const matching = ref(false)
|
||||
const pushing = ref(false)
|
||||
const queueWorkerRunning = ref(false)
|
||||
const autoQueueEnabled = ref(false)
|
||||
const queuePushResult = ref('')
|
||||
const queuePayloadText = ref('')
|
||||
const matchAsinRowsByCountry = ref<Record<string, PriceTrackAsinParsedRow[]>>({})
|
||||
@@ -787,6 +789,9 @@ async function runMatch() {
|
||||
}
|
||||
matchedItems.value = [...nextByShop.values()]
|
||||
saveMatchedItemsToStorage()
|
||||
if (autoQueueEnabled.value) {
|
||||
void processMatchedQueue()
|
||||
}
|
||||
ElMessage.success(`匹配 ${batch.length} 个店铺`)
|
||||
} catch (e) {
|
||||
ElMessage.error(e instanceof Error ? e.message : '匹配失败')
|
||||
@@ -813,6 +818,19 @@ function rowKeyForMatch(row: { shopName?: string; shopId?: number | string | nul
|
||||
return `${(row.shopName || '').trim()}\u0001${row.shopId ?? ''}`
|
||||
}
|
||||
|
||||
function buildSkipAsinDeletePolicy() {
|
||||
const enabled = statusModeEnabled.value && !asinModeEnabled.value
|
||||
return {
|
||||
enabled,
|
||||
mode: enabled ? 'DELETE_WHEN_PRICE_BELOW_MINIMUM' : 'NONE',
|
||||
deleteWhenPriceBelowMinimum: enabled,
|
||||
compareField: 'price',
|
||||
thresholdField: 'minimumPrice',
|
||||
target: 'skip_asin',
|
||||
source: 'frontend-price-track',
|
||||
}
|
||||
}
|
||||
|
||||
function removeMatchedRowsLocally(rows: Array<{ shopName?: string; shopId?: number | string | null }>) {
|
||||
if (!rows.length) return
|
||||
const keys = new Set(rows.map((row) => rowKeyForMatch(row)))
|
||||
@@ -903,6 +921,9 @@ async function pushToPythonQueueLegacy() {
|
||||
// 店铺简要信息(用于展示)
|
||||
shop_names: matchedRows.map((i) => i.shopName).filter(Boolean),
|
||||
country_codes: [...orderedCountryCodes.value],
|
||||
skip_asin_delete_policy: buildSkipAsinDeletePolicy(),
|
||||
delete_skip_asin_when_price_below_minimum: statusModeEnabled.value && !asinModeEnabled.value,
|
||||
deleteSkipAsinWhenPriceBelowMinimum: statusModeEnabled.value && !asinModeEnabled.value,
|
||||
},
|
||||
}
|
||||
queuePayloadText.value = JSON.stringify(queuePayload, null, 2)
|
||||
@@ -930,6 +951,9 @@ function buildQueuePayload(taskVo: PriceTrackCreateTaskVo, row: PriceTrackShopQu
|
||||
const taskItem = taskVo.items?.[0]
|
||||
const shopName = (row.shopName || '').trim()
|
||||
const skipAsinsByCountry = row.skipAsins || taskVo.skipAsinsByCountry || {}
|
||||
const skipAsinDetailsByCountry = taskVo.skipAsinDetailsByCountry || {}
|
||||
const minimumPriceByCountryAndAsin = taskVo.minimumPriceByCountryAndAsin || {}
|
||||
const skipAsinDeletePolicy = buildSkipAsinDeletePolicy()
|
||||
const resultId = taskItem?.resultId ?? null
|
||||
const loopRunId = taskItem?.loopRunId ?? null
|
||||
const roundIndex = taskItem?.roundIndex ?? null
|
||||
@@ -963,6 +987,11 @@ function buildQueuePayload(taskVo: PriceTrackCreateTaskVo, row: PriceTrackShopQu
|
||||
mode: statusModeEnabled.value ? 'status' : 'asin',
|
||||
skip_asins: skipAsinsByCountry,
|
||||
skip_asins_by_country: skipAsinsByCountry,
|
||||
skip_asin_details_by_country: skipAsinDetailsByCountry,
|
||||
minimum_price_by_country_and_asin: minimumPriceByCountryAndAsin,
|
||||
skip_asin_delete_policy: skipAsinDeletePolicy,
|
||||
delete_skip_asin_when_price_below_minimum: skipAsinDeletePolicy.deleteWhenPriceBelowMinimum,
|
||||
deleteSkipAsinWhenPriceBelowMinimum: skipAsinDeletePolicy.deleteWhenPriceBelowMinimum,
|
||||
asin_rows_by_country: Object.keys(matchAsinRowsByCountry.value).length
|
||||
? matchAsinRowsByCountry.value
|
||||
: (taskVo.asinRowsByCountry || {}),
|
||||
@@ -1039,6 +1068,18 @@ async function waitForTaskTerminal(taskId: number) {
|
||||
}
|
||||
|
||||
async function pushToPythonQueue() {
|
||||
autoQueueEnabled.value = true
|
||||
await processMatchedQueue()
|
||||
}
|
||||
|
||||
function nextMatchedQueueItem() {
|
||||
return matchedItems.value.find((item) => item.matched)
|
||||
}
|
||||
|
||||
async function processMatchedQueue() {
|
||||
if (queueWorkerRunning.value) {
|
||||
return
|
||||
}
|
||||
if (!hasValidMode.value) {
|
||||
ElMessage.warning('请至少选择一个跟价模式')
|
||||
return
|
||||
@@ -1057,13 +1098,19 @@ async function pushToPythonQueue() {
|
||||
ElMessage.warning('无可用匹配店铺')
|
||||
return
|
||||
}
|
||||
queueWorkerRunning.value = true
|
||||
pushing.value = true
|
||||
queuePayloadText.value = ''
|
||||
let successCount = 0
|
||||
let failedCount = 0
|
||||
try {
|
||||
for (let index = 0; index < matchedRows.length; index += 1) {
|
||||
const row = matchedRows[index]
|
||||
let index = 0
|
||||
while (autoQueueEnabled.value) {
|
||||
const row = nextMatchedQueueItem()
|
||||
if (!row) {
|
||||
break
|
||||
}
|
||||
index += 1
|
||||
try {
|
||||
let attempt = 0
|
||||
const taskVo = await (async () => {
|
||||
@@ -1107,37 +1154,38 @@ async function pushToPythonQueue() {
|
||||
failedCount += 1
|
||||
queuePushResult.value = '任务 ' + taskVo.taskId + ' 推送失败,已自动继续下一条:' + (pushResult?.error || '未知错误')
|
||||
ElMessage.error(queuePushResult.value)
|
||||
removeMatchedRowsLocally([row])
|
||||
continue
|
||||
}
|
||||
addPollingTask(taskVo.taskId)
|
||||
scheduleNextPoll(true)
|
||||
removeMatchedRowsLocally([row])
|
||||
queuePushResult.value = matchedRows.length > 1
|
||||
? '任务 ' + taskVo.taskId + ' 已入队,等待完成后继续下一条(' + (index + 1) + '/' + matchedRows.length + ')'
|
||||
: '任务 ' + taskVo.taskId + ' 已入队,等待执行完成'
|
||||
queuePushResult.value = '任务 ' + taskVo.taskId + ' 已入队,等待执行完成'
|
||||
const finalStatus = await waitForTaskTerminal(taskVo.taskId)
|
||||
if (finalStatus !== 'SUCCESS') {
|
||||
failedCount += 1
|
||||
queuePushResult.value = '任务 ' + taskVo.taskId + ' 执行失败,已自动继续下一条(' + (index + 1) + '/' + matchedRows.length + ')'
|
||||
queuePushResult.value = '任务 ' + taskVo.taskId + ' 执行失败,已自动继续下一条'
|
||||
ElMessage.error(queuePushResult.value)
|
||||
continue
|
||||
}
|
||||
successCount += 1
|
||||
queuePushResult.value = index + 1 < matchedRows.length
|
||||
? '任务 ' + taskVo.taskId + ' 已完成,继续推送下一条(' + (index + 1) + '/' + matchedRows.length + ')'
|
||||
: '任务 ' + taskVo.taskId + ' 已完成'
|
||||
queuePushResult.value = '任务 ' + taskVo.taskId + ' 已完成'
|
||||
} catch (error) {
|
||||
failedCount += 1
|
||||
queuePushResult.value = '第 ' + (index + 1) + '/' + matchedRows.length + ' 条任务处理失败,已自动继续下一条:' + (error instanceof Error ? error.message : '未知错误')
|
||||
queuePushResult.value = '第 ' + index + ' 条任务处理失败,已自动继续下一条:' + (error instanceof Error ? error.message : '未知错误')
|
||||
ElMessage.error(queuePushResult.value)
|
||||
removeMatchedRowsLocally([row])
|
||||
continue
|
||||
}
|
||||
}
|
||||
ElMessage.success('店铺任务推送已完成:成功 ' + successCount + ' 条,失败 ' + failedCount + ' 条')
|
||||
if (successCount > 0 || failedCount > 0) {
|
||||
ElMessage.success('店铺任务推送已完成:成功 ' + successCount + ' 条,失败 ' + failedCount + ' 条')
|
||||
}
|
||||
} catch (e) {
|
||||
queuePushResult.value = e instanceof Error ? e.message : '推送异常'
|
||||
ElMessage.error(queuePushResult.value)
|
||||
} finally {
|
||||
queueWorkerRunning.value = false
|
||||
pushing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user