视频任务管理更新

This commit is contained in:
super
2026-07-19 22:23:26 +08:00
parent 69784b8d32
commit cbde22ec79
62 changed files with 2164 additions and 280 deletions

View File

@@ -114,6 +114,8 @@
<div v-if="countryPrefSaving" class="country-pref-status">保存中</div>
</template>
<ZiniaoVersionSetting v-model="ziniaoVersion" />
<!-- 状态指示 -->
<div v-if="statusModeEnabled" class="mode-status-bar">
<span class="mode-status-dot active"></span>
@@ -261,12 +263,14 @@
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { ElMessage } from 'element-plus'
import BrandTopBar from '@/pages/brand/components/BrandTopBar.vue'
import ZiniaoVersionSetting from '@/shared/components/ZiniaoVersionSetting.vue'
import { LISTING_FILTER_OPTIONS, type ListingFilterValue } from '@/pages/brand/components/listingFilters'
import { expandBrandFolderRecursive } from '@/shared/api/brand'
import { getPywebviewApi, type UploadedJavaFile } from '@/shared/bridges/pywebview'
import { getPywebviewApi, type PywebviewApi, type UploadedJavaFile } from '@/shared/bridges/pywebview'
import { getTaskPollIntervalMs } from '@/shared/task-progress-config'
import { createCategorizedTimers } from '@/shared/utils/categorized-timers'
import { saveUrlWithProgress } from '@/shared/utils/download-progress'
import { useZiniaoVersion } from '@/shared/utils/ziniao-version'
import {
addPriceTrackCandidate,
completePriceTrackLoopChild,
@@ -287,6 +291,7 @@ import {
getTaskSkipPriceAsinsPaginated,
listPriceTrackCandidates,
matchPriceTrackShops,
markPriceTrackDispatchFailed,
putPriceTrackCountryPreference,
stopPriceTrackLoopRun,
type PriceTrackAsinParsedRow,
@@ -300,6 +305,8 @@ import {
type PriceTrackTaskDetailVo,
} from '@/shared/api/java-modules'
const ziniaoVersion = useZiniaoVersion()
// ========== 类型定义 ==========
const COUNTRY_OPTIONS = [
{ code: 'DE', label: '德国' },
@@ -1011,6 +1018,7 @@ async function pushToPythonQueueLegacy() {
ts: Date.now(),
data: {
task_id: taskVo.taskId,
ziniao_version: ziniaoVersion.value,
shop_name: (firstRow.shopName || '').trim(),
shopName: (firstRow.shopName || '').trim(),
companyName: firstRow.companyName || '',
@@ -1023,16 +1031,11 @@ async function pushToPythonQueueLegacy() {
}
queuePayloadText.value = JSON.stringify(queuePayload, null, 2)
const pushResult = await api.enqueue_json(queuePayload)
if (pushResult?.success) {
queuePushResult.value = `任务 ${taskVo.taskId} 已入队,等待执行完成...`
addPollingTask(taskVo.taskId)
scheduleNextPoll(true)
ElMessage.success('已推送到 Python 队列')
} else {
queuePushResult.value = `推送失败:${pushResult?.error || '未知错误'}`
ElMessage.error(queuePushResult.value)
}
await enqueueCreatedTask(api, taskVo.taskId, queuePayload)
queuePushResult.value = `任务 ${taskVo.taskId} 已入队,等待执行完成...`
addPollingTask(taskVo.taskId)
scheduleNextPoll(true)
ElMessage.success('已推送到 Python 队列')
} catch (e) {
queuePushResult.value = e instanceof Error ? e.message : '推送异常'
ElMessage.error(queuePushResult.value)
@@ -1052,6 +1055,7 @@ async function buildQueuePayload(taskVo: PriceTrackCreateTaskVo, row: PriceTrack
ts: Date.now(),
data: {
task_id: taskVo.taskId,
ziniao_version: ziniaoVersion.value,
shop_name: shopName,
country_codes: resolveCountryCodesForRequest(),
mode: priceTrackModeForAppClient(),
@@ -1064,6 +1068,42 @@ async function buildQueuePayload(taskVo: PriceTrackCreateTaskVo, row: PriceTrack
}
}
async function enqueueCreatedTask(api: PywebviewApi, taskId: number, queuePayload: unknown) {
if (!api.enqueue_json) throw new Error('当前环境未启用 pywebview enqueue_json')
let pushResult: Awaited<ReturnType<NonNullable<PywebviewApi['enqueue_json']>>>
try {
pushResult = await api.enqueue_json(queuePayload)
} catch (error) {
const reason = `Python 队列调用异常:${error instanceof Error ? error.message : String(error || '未知错误')}`
await compensateDispatchFailure(taskId, reason)
throw new Error(reason)
}
if (!pushResult?.success) {
const reason = pushResult?.error || 'Python 队列拒绝接收任务'
await compensateDispatchFailure(taskId, reason)
throw new Error(reason)
}
return pushResult
}
async function compensateDispatchFailure(taskId: number, reason: string) {
try {
await markPriceTrackDispatchFailed(taskId, reason)
removePollingTask(taskId)
taskDetails.value = { ...taskDetails.value, [taskId]: 'FAILED' }
saveTaskDetailsToStorage()
await loadHistory()
await loadDashboard()
syncPollingIdsWithHistory()
if (activeLoopRunId.value) await syncActiveLoopRun()
} catch (error) {
addPollingTask(taskId)
scheduleNextPoll(true)
const syncError = error instanceof Error ? error.message : String(error || '未知错误')
throw new Error(`${reason};后端失败状态同步失败:${syncError}`)
}
}
async function waitForTaskTerminal(taskId: number) {
let transientErrorCount = 0
const maxTransientErrors = 30
@@ -1203,14 +1243,7 @@ async function processMatchedQueue() {
saveTaskDetailsToStorage()
const queuePayload = await buildQueuePayload(taskVo, row)
queuePayloadText.value = JSON.stringify(queuePayload, null, 2)
const pushResult = await api.enqueue_json(queuePayload)
if (!pushResult?.success) {
failedCount += 1
queuePushResult.value = '任务 ' + taskVo.taskId + ' 推送失败,已自动继续下一条:' + (pushResult?.error || '未知错误')
ElMessage.error(queuePushResult.value)
removeMatchedRowsLocally([row])
continue
}
await enqueueCreatedTask(api, taskVo.taskId, queuePayload)
addPollingTask(taskVo.taskId)
scheduleNextPoll(true)
removeMatchedRowsLocally([row])
@@ -1404,10 +1437,7 @@ async function runLoopExecution(loopId?: number) {
recordCreatedTask(taskVo)
const queuePayload = await buildQueuePayload(taskVo, row)
queuePayloadText.value = JSON.stringify(queuePayload, null, 2)
const pushResult = await api.enqueue_json(queuePayload)
if (!pushResult?.success) {
throw new Error(pushResult?.error || `任务 ${taskVo.taskId} 推送失败`)
}
await enqueueCreatedTask(api, taskVo.taskId, queuePayload)
addPollingTask(taskVo.taskId)
scheduleNextPoll(true)
removeMatchedRowsLocally([row])