更新带货视频工作流接口和页面
This commit is contained in:
@@ -284,6 +284,7 @@ import {
|
||||
getPriceTrackResultDownloadUrl,
|
||||
getPriceTrackTaskProgressBatch,
|
||||
getPriceTrackTasksBatch,
|
||||
getTaskSkipPriceAsinsPaginated,
|
||||
listPriceTrackCandidates,
|
||||
matchPriceTrackShops,
|
||||
putPriceTrackCountryPreference,
|
||||
@@ -844,17 +845,64 @@ function isRecordMissingError(error: unknown) {
|
||||
return /记录不存在|不存在|已删除|not\s*found|404/i.test(message)
|
||||
}
|
||||
|
||||
function buildSkipAsinDeletePolicy() {
|
||||
const enabled = statusModeEnabled.value && !asinModeEnabled.value
|
||||
return {
|
||||
enabled,
|
||||
mode: enabled ? 'DELETE_WHEN_PRICE_BELOW_MINIMUM' : 'NONE',
|
||||
delete_when_price_below_minimum: enabled,
|
||||
compare_field: 'price',
|
||||
threshold_field: 'minimum_price',
|
||||
target: 'skip_asin',
|
||||
source: 'frontend-price-track',
|
||||
function priceTrackModeForAppClient() {
|
||||
return statusModeEnabled.value ? 'status' : 'asin'
|
||||
}
|
||||
|
||||
function buildMinimumPriceByCountryAndAsin(rowsByCountry: Record<string, PriceTrackAsinParsedRow[]>) {
|
||||
const out: Record<string, Record<string, string>> = {}
|
||||
for (const [country, rows] of Object.entries(rowsByCountry || {})) {
|
||||
const bucket: Record<string, string> = {}
|
||||
for (const row of rows || []) {
|
||||
const asin = (row.asin || '').trim()
|
||||
if (!asin) continue
|
||||
bucket[asin] = row.minimumPrice == null ? '' : String(row.minimumPrice)
|
||||
}
|
||||
out[country] = bucket
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
function hasCountryRows(rowsByCountry: Record<string, PriceTrackAsinParsedRow[]> | undefined) {
|
||||
return Object.values(rowsByCountry || {}).some((rows) => Array.isArray(rows) && rows.length > 0)
|
||||
}
|
||||
|
||||
function hasMinimumPriceMap(map: Record<string, Record<string, string>> | undefined) {
|
||||
return Object.values(map || {}).some((rows) => rows && Object.keys(rows).length > 0)
|
||||
}
|
||||
|
||||
function buildMinimumPriceMapForAppClient(taskVo: PriceTrackCreateTaskVo, asinRowsByCountry: Record<string, PriceTrackAsinParsedRow[]>) {
|
||||
return hasMinimumPriceMap(taskVo.minimumPriceByCountryAndAsin)
|
||||
? taskVo.minimumPriceByCountryAndAsin || {}
|
||||
: buildMinimumPriceByCountryAndAsin(asinRowsByCountry)
|
||||
}
|
||||
|
||||
async function loadAsinRowsForAppClient(taskVo: PriceTrackCreateTaskVo) {
|
||||
const fromTask = taskVo.asinRowsByCountry || {}
|
||||
if (hasCountryRows(fromTask)) {
|
||||
return fromTask
|
||||
}
|
||||
if (!asinModeEnabled.value) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const merged: Record<string, PriceTrackAsinParsedRow[]> = {}
|
||||
let page = 1
|
||||
let totalPages = 1
|
||||
do {
|
||||
const res = await getTaskSkipPriceAsinsPaginated(taskVo.taskId, page, 2000)
|
||||
totalPages = Math.max(1, Number(res.totalPages) || 1)
|
||||
const pageRows = (res.asin_rows_by_country || res.skipAsinDetailsByCountry || res.skip_asin_details_by_country || {}) as Record<
|
||||
string,
|
||||
PriceTrackAsinParsedRow[]
|
||||
>
|
||||
for (const [country, rows] of Object.entries(pageRows)) {
|
||||
merged[country] = [...(merged[country] || []), ...(rows || [])]
|
||||
}
|
||||
page += 1
|
||||
} while (page <= totalPages)
|
||||
|
||||
return merged
|
||||
}
|
||||
|
||||
function removeMatchedRowsLocally(rows: Array<{ shopName?: string; shopId?: number | string | null }>) {
|
||||
@@ -953,20 +1001,24 @@ async function pushToPythonQueueLegacy() {
|
||||
saveTaskSnapshotsToStorage()
|
||||
saveTaskDetailsToStorage()
|
||||
|
||||
// 2. 推送 taskId 给 Python,Python 会从 Java 拉取完整任务上下文
|
||||
const firstRow = matchedRows[0]
|
||||
const asinRowsByCountry = await loadAsinRowsForAppClient(taskVo)
|
||||
const minimumPriceByCountryAndAsin = buildMinimumPriceMapForAppClient(taskVo, asinRowsByCountry)
|
||||
|
||||
// 2. 推送 app_client 当前消费的字段
|
||||
const queuePayload = {
|
||||
type: 'price-track-run',
|
||||
ts: Date.now(),
|
||||
data: {
|
||||
task_id: taskVo.taskId,
|
||||
shop_names: matchedRows.map((i) => i.shopName).filter(Boolean),
|
||||
shop_name: (firstRow.shopName || '').trim(),
|
||||
shopName: (firstRow.shopName || '').trim(),
|
||||
companyName: firstRow.companyName || '',
|
||||
shopMallName: firstRow.shopMallName || '',
|
||||
country_codes: resolveCountryCodesForRequest(),
|
||||
use_skip_asin_check: statusModeEnabled.value && !asinModeEnabled.value,
|
||||
skip_asin_check_url: `/api/price-track/tasks/${taskVo.taskId}/skip-asin/check`,
|
||||
use_paginated_skip_asins: false,
|
||||
skip_asin_page_size: 0,
|
||||
skip_asin_delete_policy: buildSkipAsinDeletePolicy(),
|
||||
delete_skip_asin_when_price_below_minimum: statusModeEnabled.value && !asinModeEnabled.value,
|
||||
mode: priceTrackModeForAppClient(),
|
||||
asin_rows_by_country: asinRowsByCountry,
|
||||
minimum_price_by_country_and_asin: minimumPriceByCountryAndAsin,
|
||||
},
|
||||
}
|
||||
queuePayloadText.value = JSON.stringify(queuePayload, null, 2)
|
||||
@@ -990,49 +1042,24 @@ async function pushToPythonQueueLegacy() {
|
||||
}
|
||||
|
||||
// ========== 任务状态轮询 ==========
|
||||
function buildQueuePayload(taskVo: PriceTrackCreateTaskVo, row: PriceTrackShopQueueItem) {
|
||||
const taskItem = taskVo.items?.[0]
|
||||
async function buildQueuePayload(taskVo: PriceTrackCreateTaskVo, row: PriceTrackShopQueueItem) {
|
||||
const shopName = (row.shopName || '').trim()
|
||||
const skipAsinDeletePolicy = buildSkipAsinDeletePolicy()
|
||||
const skipAsinCheckPath = `/api/price-track/tasks/${taskVo.taskId}/skip-asin/check`
|
||||
const resultId = taskItem?.resultId ?? null
|
||||
const loopRunId = taskItem?.loopRunId ?? null
|
||||
const roundIndex = taskItem?.roundIndex ?? null
|
||||
const taskStatus = taskItem?.taskStatus || 'RUNNING'
|
||||
const success = taskItem?.success ?? false
|
||||
const error = taskItem?.error || null
|
||||
const outputFilename = taskItem?.outputFilename || null
|
||||
const downloadUrl = taskItem?.downloadUrl || null
|
||||
const asinRowsByCountry = await loadAsinRowsForAppClient(taskVo)
|
||||
const minimumPriceByCountryAndAsin = buildMinimumPriceMapForAppClient(taskVo, asinRowsByCountry)
|
||||
|
||||
return {
|
||||
type: 'price-track-run',
|
||||
ts: Date.now(),
|
||||
data: {
|
||||
task_id: taskVo.taskId,
|
||||
result_id: resultId,
|
||||
shop_name: shopName,
|
||||
shop_id: row.shopId ?? null,
|
||||
platform: row.platform || '',
|
||||
company_name: row.companyName || '',
|
||||
shop_mall_name: row.shopMallName || '',
|
||||
matched: !!row.matched,
|
||||
match_status: row.matchStatus || '',
|
||||
match_message: row.matchMessage || null,
|
||||
success: success,
|
||||
error: error,
|
||||
output_filename: outputFilename,
|
||||
download_url: downloadUrl,
|
||||
task_status: taskStatus,
|
||||
loop_run_id: loopRunId,
|
||||
round_index: roundIndex,
|
||||
country_codes: resolveCountryCodesForRequest(),
|
||||
mode: statusModeEnabled.value ? 'status' : 'asin',
|
||||
use_skip_asin_check: statusModeEnabled.value && !asinModeEnabled.value,
|
||||
skip_asin_check_url: skipAsinCheckPath,
|
||||
use_paginated_skip_asins: false,
|
||||
skip_asin_page_size: 0,
|
||||
skip_asin_delete_policy: skipAsinDeletePolicy,
|
||||
delete_skip_asin_when_price_below_minimum: skipAsinDeletePolicy.delete_when_price_below_minimum,
|
||||
mode: priceTrackModeForAppClient(),
|
||||
shopName,
|
||||
companyName: row.companyName || '',
|
||||
shopMallName: row.shopMallName || '',
|
||||
asin_rows_by_country: asinRowsByCountry,
|
||||
minimum_price_by_country_and_asin: minimumPriceByCountryAndAsin,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1174,7 +1201,7 @@ async function processMatchedQueue() {
|
||||
}
|
||||
saveTaskSnapshotsToStorage()
|
||||
saveTaskDetailsToStorage()
|
||||
const queuePayload = buildQueuePayload(taskVo, row)
|
||||
const queuePayload = await buildQueuePayload(taskVo, row)
|
||||
queuePayloadText.value = JSON.stringify(queuePayload, null, 2)
|
||||
const pushResult = await api.enqueue_json(queuePayload)
|
||||
if (!pushResult?.success) {
|
||||
@@ -1375,7 +1402,7 @@ async function runLoopExecution(loopId?: number) {
|
||||
}
|
||||
})()
|
||||
recordCreatedTask(taskVo)
|
||||
const queuePayload = buildQueuePayload(taskVo, row)
|
||||
const queuePayload = await buildQueuePayload(taskVo, row)
|
||||
queuePayloadText.value = JSON.stringify(queuePayload, null, 2)
|
||||
const pushResult = await api.enqueue_json(queuePayload)
|
||||
if (!pushResult?.success) {
|
||||
|
||||
Reference in New Issue
Block a user