视频任务管理更新
This commit is contained in:
@@ -50,6 +50,8 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<ZiniaoVersionSetting v-model="ziniaoVersion" />
|
||||
|
||||
<div class="run-row">
|
||||
<button type="button" class="btn-run" :disabled="running" @click="submitRun">
|
||||
{{ running ? '解析中...' : '开始解析' }}
|
||||
@@ -211,6 +213,7 @@
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import BrandTopBar from './BrandTopBar.vue'
|
||||
import ZiniaoVersionSetting from '@/shared/components/ZiniaoVersionSetting.vue'
|
||||
import { expandBrandFolderRecursive, type BrandExpandFolderItem } from '@/shared/api/brand'
|
||||
import {
|
||||
deleteDeleteBrandHistory,
|
||||
@@ -229,12 +232,15 @@ import { getPywebviewApi, type UploadedJavaFile } from '@/shared/bridges/pywebvi
|
||||
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'
|
||||
|
||||
interface SessionDeleteBrandItem extends DeleteBrandResultItem {
|
||||
_pushed?: boolean
|
||||
_completed?: boolean
|
||||
}
|
||||
|
||||
const ziniaoVersion = useZiniaoVersion()
|
||||
|
||||
interface StoredCurrentTask {
|
||||
taskId: number
|
||||
items: SessionDeleteBrandItem[]
|
||||
@@ -1307,6 +1313,7 @@ async function runItem(item: DeleteBrandResultItem, options?: { auto?: boolean }
|
||||
ts: Date.now(),
|
||||
data: {
|
||||
taskId: taskId,
|
||||
ziniao_version: ziniaoVersion.value,
|
||||
items: [item]
|
||||
},
|
||||
}
|
||||
|
||||
@@ -113,6 +113,8 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<ZiniaoVersionSetting v-model="ziniaoVersion" />
|
||||
|
||||
<div class="run-row">
|
||||
<button
|
||||
type="button"
|
||||
@@ -393,9 +395,12 @@ import { getPywebviewApi } 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 ZiniaoVersionSetting from "@/shared/components/ZiniaoVersionSetting.vue";
|
||||
import { useZiniaoVersion } from "@/shared/utils/ziniao-version";
|
||||
|
||||
const COUNTRY_TEMPLATE = ["德国", "英国", "法国", "意大利", "西班牙"] as const;
|
||||
const MAX_TRANSIENT_ERRORS = 30;
|
||||
const ziniaoVersion = useZiniaoVersion();
|
||||
|
||||
const shopInput = ref("");
|
||||
const conditionInput = ref("");
|
||||
@@ -999,6 +1004,7 @@ function buildQueuePayload(taskId: number, items: PatrolDeleteHistoryItem[]) {
|
||||
ts: Date.now(),
|
||||
data: {
|
||||
taskId,
|
||||
ziniao_version: ziniaoVersion.value,
|
||||
user_id: Number(uidForStorage()) || 0,
|
||||
source: "frontend-vue-patrol-delete",
|
||||
delete_conditions: deleteConditionsForTask,
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<ZiniaoVersionSetting v-model="ziniaoVersion" />
|
||||
|
||||
<div class="run-row">
|
||||
<button type="button" class="btn-run" :disabled="matching" @click="runMatch">
|
||||
{{ matching ? '匹配中…' : '匹配店铺' }}
|
||||
@@ -222,6 +224,8 @@ import { getPywebviewApi } 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 ZiniaoVersionSetting from '@/shared/components/ZiniaoVersionSetting.vue'
|
||||
import { useZiniaoVersion } from '@/shared/utils/ziniao-version'
|
||||
|
||||
const shopInput = ref('')
|
||||
const candidates = ref<ProductRiskCandidateVo[]>([])
|
||||
@@ -234,6 +238,7 @@ const queueWorkerRunning = ref(false)
|
||||
const autoQueueEnabled = ref(false)
|
||||
const queuePushResult = ref('')
|
||||
const queuePayloadText = ref('')
|
||||
const ziniaoVersion = useZiniaoVersion()
|
||||
|
||||
const PRODUCT_RISK_LISTING_FILTER_OPTIONS = [
|
||||
...LISTING_FILTER_OPTIONS,
|
||||
@@ -1078,6 +1083,7 @@ async function processMatchedBatchQueue(toPush: ProductRiskShopQueueItem[]) {
|
||||
ts: Date.now(),
|
||||
data: {
|
||||
taskId,
|
||||
ziniao_version: ziniaoVersion.value,
|
||||
items: toPush,
|
||||
country_codes: [...orderedCountryCodes.value],
|
||||
risk_listing_filter: productRiskListingFilter.value,
|
||||
@@ -1155,6 +1161,7 @@ async function processMatchedQueue() {
|
||||
ts: Date.now(),
|
||||
data: {
|
||||
taskId,
|
||||
ziniao_version: ziniaoVersion.value,
|
||||
items: [item],
|
||||
country_codes: [...orderedCountryCodes.value],
|
||||
risk_listing_filter: productRiskListingFilter.value,
|
||||
|
||||
@@ -60,6 +60,8 @@
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<ZiniaoVersionSetting v-model="ziniaoVersion" />
|
||||
|
||||
<div class="run-row">
|
||||
<button
|
||||
type="button"
|
||||
@@ -341,8 +343,11 @@ import { getPywebviewApi } 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 ZiniaoVersionSetting from "@/shared/components/ZiniaoVersionSetting.vue";
|
||||
import { useZiniaoVersion } from "@/shared/utils/ziniao-version";
|
||||
|
||||
const MAX_TRANSIENT_ERRORS = 30;
|
||||
const ziniaoVersion = useZiniaoVersion();
|
||||
|
||||
const shopInput = ref("");
|
||||
const candidates = ref<QueryAsinCandidateVo[]>([]);
|
||||
@@ -937,6 +942,7 @@ function buildQueuePayload(taskId: number, item: QueryAsinHistoryItem) {
|
||||
ts: Date.now(),
|
||||
data: {
|
||||
taskId,
|
||||
ziniao_version: ziniaoVersion.value,
|
||||
user_id: Number(uidForStorage()) || 0,
|
||||
source: "frontend-vue-query-asin",
|
||||
submissionId,
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
<button type="button" class="schedule-add" :disabled="pushing" @click="addScheduleValue">添加时间点</button>
|
||||
<p class="hint schedule-hint">默认开启定时;支持按 `MM-DD HH:mm` 配置多个时间点,前端不再限制选择更早时间,实际是否可执行以后端校验为准。</p>
|
||||
</div>
|
||||
<ZiniaoVersionSetting v-model="ziniaoVersion" />
|
||||
|
||||
<div class="run-row">
|
||||
<button type="button" class="btn-run" :disabled="matching" @click="runMatch">{{ matching ? '匹配中...' : '匹配店铺' }}</button>
|
||||
<button type="button" class="btn-run btn-queue" :disabled="pushing || !matchedItems.length" @click="pushToPythonQueue">{{ pushing ? '推送中...' : scheduleEnabled ? '创建定时任务' : '推送到 Python 队列' }}</button>
|
||||
@@ -107,12 +109,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 { activateShopMatchTask, addShopMatchCandidate, createShopMatchTask, deleteShopMatchCandidate, deleteShopMatchHistory, deleteShopMatchTask, getShopMatchCountryPreference, getShopMatchDashboard, getShopMatchHistory, getShopMatchResultDownloadUrl, getShopMatchTaskProgressBatch, getShopMatchTasksBatch, listShopMatchCandidates, matchShopMatchShops, putShopMatchCountryPreference, type ShopMatchCandidateVo, type ShopMatchCreateTaskItem, type ShopMatchDashboardVo, type ShopMatchHistoryItem, type ShopMatchShopQueueItem, type ShopMatchTaskDetailVo } from '@/shared/api/java-modules'
|
||||
import { getPywebviewApi } 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'
|
||||
|
||||
const COUNTRY_OPTIONS = [{ code: 'DE', label: '德国' }, { code: 'UK', label: '英国' }, { code: 'FR', label: '法国' }, { code: 'IT', label: '意大利' }, { code: 'ES', label: '西班牙' }] as const
|
||||
const shopInput = ref('')
|
||||
@@ -127,6 +131,7 @@ const queueWorkerRunning = ref(false)
|
||||
const autoQueueEnabled = ref(false)
|
||||
const queuePushResult = ref('')
|
||||
const queuePayloadText = ref('')
|
||||
const ziniaoVersion = useZiniaoVersion()
|
||||
const orderedCountryCodes = ref<string[]>(['DE', 'UK', 'FR', 'IT', 'ES'])
|
||||
const dragCountryIndex = ref<number | null>(null)
|
||||
const countryPrefSaving = ref(false)
|
||||
@@ -325,6 +330,7 @@ function buildQueuePayload(taskId: number, item: Pick<ShopMatchHistoryItem, 'sho
|
||||
ts: Date.now(),
|
||||
data: {
|
||||
taskId,
|
||||
ziniao_version: ziniaoVersion.value,
|
||||
user_id: currentUserId(),
|
||||
items: [{
|
||||
shopName: item.shopName,
|
||||
|
||||
@@ -71,6 +71,8 @@
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<ZiniaoVersionSetting v-model="ziniaoVersion" />
|
||||
|
||||
<div class="run-row">
|
||||
<button
|
||||
type="button"
|
||||
@@ -354,8 +356,11 @@ import { getPywebviewApi } 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 ZiniaoVersionSetting from "@/shared/components/ZiniaoVersionSetting.vue";
|
||||
import { useZiniaoVersion } from "@/shared/utils/ziniao-version";
|
||||
|
||||
const MAX_TRANSIENT_ERRORS = 30;
|
||||
const ziniaoVersion = useZiniaoVersion();
|
||||
|
||||
type WithdrawTaskBatchQueueItem = {
|
||||
batchId: string;
|
||||
@@ -1048,6 +1053,7 @@ function buildQueuePayload(taskId: number, batch: WithdrawTaskBatchQueueItem) {
|
||||
ts: Date.now(),
|
||||
data: {
|
||||
task_id: taskId,
|
||||
ziniao_version: ziniaoVersion.value,
|
||||
user_id: Number(uidForStorage()) || 0,
|
||||
source: "frontend-vue-withdraw",
|
||||
reserved_amount: batch.reservedAmount,
|
||||
|
||||
Reference in New Issue
Block a user