chore: 移除项目内无用代码(28 文件)
- 清理任务面板/SPA 化改造遗留的未使用变量与函数(模板管理配套 6 函数、 payloadForDisplay/showTip/hasRunning/schedulePoll/removeMatchedRowLocally 等 30+ 处) - 清理未使用 import(getBrandTemplateXlsxUrl/uploadTempFileToJava/getProductRiskTasksBatch 等) - useTaskProgressLoop 改为仅类型导入;progress/task-request 缓存未用参数精简 - DeleteBrandRunService 删除永不执行的 taskItems 死分支 - 全量 vue-tsc(含 --noUnusedLocals/--noUnusedParameters)0 错误;648 测试全过
This commit is contained in:
-33
@@ -379,39 +379,6 @@ public class DeleteBrandRunService {
|
|||||||
FileTaskEntity taskEntity = taskById.get(entity.getTaskId());
|
FileTaskEntity taskEntity = taskById.get(entity.getTaskId());
|
||||||
item.setCreatedAt(fmt(taskEntity == null ? null : taskEntity.getCreatedAt()));
|
item.setCreatedAt(fmt(taskEntity == null ? null : taskEntity.getCreatedAt()));
|
||||||
item.setFinishedAt(fmt(taskEntity == null ? null : taskEntity.getFinishedAt()));
|
item.setFinishedAt(fmt(taskEntity == null ? null : taskEntity.getFinishedAt()));
|
||||||
List<DeleteBrandResultItemVo> taskItems = null;
|
|
||||||
if (taskItems != null && entity.getSourceFilename() != null && !entity.getSourceFilename().isBlank()) {
|
|
||||||
for (DeleteBrandResultItemVo candidate : taskItems) {
|
|
||||||
if (candidate == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (entity.getSourceFilename().equals(candidate.getSourceFilename())) {
|
|
||||||
item.setMatched(candidate.isMatched());
|
|
||||||
item.setMatchStatus(candidate.getMatchStatus());
|
|
||||||
item.setMatchMessage(candidate.getMatchMessage());
|
|
||||||
// 如果物理结果已经成功,说明已经处理过,强制标记为匹配成功
|
|
||||||
if (item.isSuccess() && candidate.getShopId() != null && !candidate.getShopId().isBlank()) {
|
|
||||||
item.setMatched(true);
|
|
||||||
item.setMatchStatus(ZiniaoShopIndexService.MATCH_STATUS_MATCHED);
|
|
||||||
item.setMatchMessage(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
item.setShopId(candidate.getShopId());
|
|
||||||
item.setCompanyName(candidate.getCompanyName());
|
|
||||||
item.setPlatform(candidate.getPlatform());
|
|
||||||
item.setOpenStoreUrl(candidate.getOpenStoreUrl());
|
|
||||||
|
|
||||||
// 历史表里可能只有通用 errorMessage,优先返回任务当时的真实 error
|
|
||||||
// 但如果物理结果已成功,就不应该再显示所谓“未匹配”的报错
|
|
||||||
if (item.isSuccess()) {
|
|
||||||
item.setError(null);
|
|
||||||
} else if ((item.getError() == null || item.getError().isBlank()) && candidate.getError() != null && !candidate.getError().isBlank()) {
|
|
||||||
item.setError(candidate.getError());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
}).toList());
|
}).toList());
|
||||||
|
|||||||
@@ -258,24 +258,6 @@ function effectivePatentToken() {
|
|||||||
return getStoredApiSecret('appearance-patent-token').trim()
|
return getStoredApiSecret('appearance-patent-token').trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function maskSecret(secret: string) {
|
|
||||||
if (!secret) return ''
|
|
||||||
if (secret.length <= 10) return '***'
|
|
||||||
return `${secret.slice(0, 6)}***${secret.slice(-4)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
function payloadForDisplay<T extends { data?: Record<string, unknown> }>(payload: T) {
|
|
||||||
return {
|
|
||||||
...payload,
|
|
||||||
data: payload.data
|
|
||||||
? {
|
|
||||||
...payload.data,
|
|
||||||
api_key: maskSecret(String(payload.data.api_key || '')),
|
|
||||||
patent_token: maskSecret(String(payload.data.patent_token || '')),
|
|
||||||
}
|
|
||||||
: payload.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function uidForStorage() {
|
function uidForStorage() {
|
||||||
return typeof window !== 'undefined' ? window.localStorage.getItem('uid') || '0' : '0'
|
return typeof window !== 'undefined' ? window.localStorage.getItem('uid') || '0' : '0'
|
||||||
|
|||||||
@@ -159,9 +159,6 @@ function baseName(path: string) {
|
|||||||
|
|
||||||
let pollTimer: number | null = null
|
let pollTimer: number | null = null
|
||||||
|
|
||||||
function hasRunning() {
|
|
||||||
return tasks.value.some((item) => isRunning(item))
|
|
||||||
}
|
|
||||||
|
|
||||||
function isRunning(item: BrandTaskItem) {
|
function isRunning(item: BrandTaskItem) {
|
||||||
return (item.status || '').toLowerCase() === 'running'
|
return (item.status || '').toLowerCase() === 'running'
|
||||||
@@ -452,19 +449,6 @@ async function downloadTemplate(kind: 'xlsx' | 'zip') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function schedulePoll() {
|
|
||||||
if (pollTimer) {
|
|
||||||
window.clearTimeout(pollTimer)
|
|
||||||
pollTimer = null
|
|
||||||
}
|
|
||||||
pollTimer = window.setTimeout(async () => {
|
|
||||||
await loadTasks()
|
|
||||||
if (hasRunning()) {
|
|
||||||
schedulePoll()
|
|
||||||
}
|
|
||||||
}, 3000)
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
void loadTasks()
|
void loadTasks()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -264,11 +264,6 @@ const progressLoop = useTaskProgressLoop<CollectDataTaskDetailVo>({
|
|||||||
|
|
||||||
const displayFileNames = computed(() => selectedFileNames.value.slice(0, 8))
|
const displayFileNames = computed(() => selectedFileNames.value.slice(0, 8))
|
||||||
|
|
||||||
function countryLabel(code: string) {
|
|
||||||
const row = COUNTRY_OPTIONS.find((o) => o.code === code)
|
|
||||||
return row?.label ?? code
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectCountry(code: string) {
|
function selectCountry(code: string) {
|
||||||
if (!COUNTRY_OPTIONS.some((row) => row.code === code)) return
|
if (!COUNTRY_OPTIONS.some((row) => row.code === code)) return
|
||||||
if (selectedCountryCode.value === code) return
|
if (selectedCountryCode.value === code) return
|
||||||
|
|||||||
@@ -154,17 +154,14 @@ import { ElMessage } from 'element-plus'
|
|||||||
import AmazonToolPageShell from '@/pages/amazon/components/AmazonToolPageShell.vue';
|
import AmazonToolPageShell from '@/pages/amazon/components/AmazonToolPageShell.vue';
|
||||||
import TaskCenterPanel from '@/shared/components/tasks/TaskCenterPanel.vue'
|
import TaskCenterPanel from '@/shared/components/tasks/TaskCenterPanel.vue'
|
||||||
import type { TaskItemView, TaskStatCard } from '@/shared/components/tasks/types'
|
import type { TaskItemView, TaskStatCard } from '@/shared/components/tasks/types'
|
||||||
import { expandBrandFolderRecursive, getBrandTemplateXlsxUrl, getBrandTemplateZipUrl } from '@/shared/api/brand'
|
import { expandBrandFolderRecursive } from '@/shared/api/brand'
|
||||||
import type { BrandExpandFolderItem } from '@/shared/api/brand'
|
import type { BrandExpandFolderItem } from '@/shared/api/brand'
|
||||||
import {
|
import {
|
||||||
deleteConvertHistory,
|
deleteConvertHistory,
|
||||||
deleteConvertTemplate,
|
|
||||||
getConvertHistory,
|
getConvertHistory,
|
||||||
getConvertResultDownloadUrl,
|
getConvertResultDownloadUrl,
|
||||||
getConvertTemplates,
|
getConvertTemplates,
|
||||||
importConvertTemplate,
|
|
||||||
runConvert,
|
runConvert,
|
||||||
setDefaultConvertTemplate,
|
|
||||||
type ConvertResultItem,
|
type ConvertResultItem,
|
||||||
type ConvertTemplateVo,
|
type ConvertTemplateVo,
|
||||||
} from '@/shared/api/java-modules'
|
} from '@/shared/api/java-modules'
|
||||||
@@ -180,18 +177,11 @@ const convertRunning = ref(false)
|
|||||||
const convertResultItems = ref<ConvertResultItem[]>([])
|
const convertResultItems = ref<ConvertResultItem[]>([])
|
||||||
const convertTemplates = ref<ConvertTemplateVo[]>([])
|
const convertTemplates = ref<ConvertTemplateVo[]>([])
|
||||||
const convertTemplateId = ref('')
|
const convertTemplateId = ref('')
|
||||||
const templateUploading = ref(false)
|
|
||||||
const templateSavingDefault = ref(false)
|
|
||||||
const templateDeleting = ref(false)
|
|
||||||
const templateInputRef = ref<HTMLInputElement>()
|
|
||||||
|
|
||||||
const convertDisplayPaths = computed(() => convertSelectedPaths.value.slice(0, 8))
|
const convertDisplayPaths = computed(() => convertSelectedPaths.value.slice(0, 8))
|
||||||
const currentConvertTemplate = computed(
|
const currentConvertTemplate = computed(
|
||||||
() => convertTemplates.value.find((item) => item.id === convertTemplateId.value) || null,
|
() => convertTemplates.value.find((item) => item.id === convertTemplateId.value) || null,
|
||||||
)
|
)
|
||||||
const canDeleteCurrentTemplate = computed(
|
|
||||||
() => Boolean(currentConvertTemplate.value && !currentConvertTemplate.value.builtIn),
|
|
||||||
)
|
|
||||||
|
|
||||||
// ---- 右侧任务面板统一视图(TaskCenterPanel)----
|
// ---- 右侧任务面板统一视图(TaskCenterPanel)----
|
||||||
const convertCards = computed<TaskStatCard[]>(() => [
|
const convertCards = computed<TaskStatCard[]>(() => [
|
||||||
@@ -362,127 +352,6 @@ async function selectConvertFolder() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openTemplatePicker() {
|
|
||||||
templateInputRef.value?.click()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleTemplateFileChange(event: Event) {
|
|
||||||
const input = event.target as HTMLInputElement
|
|
||||||
const file = input.files?.[0]
|
|
||||||
input.value = ''
|
|
||||||
|
|
||||||
if (!file) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 浏览器侧直接读内容的唯一入口:扩展名与内容都在这里拦,空模板传上去后
|
|
||||||
// 转换阶段每个文件都会失败,不如在上传时就说清楚。
|
|
||||||
if (!(await passGuard(checkSelectedFiles([file.name], { allowedExtensions: ['.txt'] })))) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
templateUploading.value = true
|
|
||||||
const templateContent = await file.text()
|
|
||||||
if (!templateContent.trim()) {
|
|
||||||
await passGuard(
|
|
||||||
guardBlocked(
|
|
||||||
'模板内容为空',
|
|
||||||
`${file.name} 里没有任何内容。\n空模板无法用于格式转换,请填好列映射后重新上传。`,
|
|
||||||
'convert.empty-template',
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const templateName = file.name.replace(/\.[^.]+$/, '') || file.name
|
|
||||||
|
|
||||||
const template = await importConvertTemplate({
|
|
||||||
templateName,
|
|
||||||
templateContent,
|
|
||||||
})
|
|
||||||
|
|
||||||
await loadConvertTemplates(template.id)
|
|
||||||
ElMessage.success(`模板已上传:${template.templateName}`)
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error(error instanceof Error ? error.message : '模板上传失败')
|
|
||||||
} finally {
|
|
||||||
templateUploading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function saveCurrentTemplateAsDefault() {
|
|
||||||
if (!currentConvertTemplate.value) {
|
|
||||||
ElMessage.warning('请先选择模板')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
templateSavingDefault.value = true
|
|
||||||
await setDefaultConvertTemplate(currentConvertTemplate.value.templateCode || currentConvertTemplate.value.id)
|
|
||||||
await loadConvertTemplates(currentConvertTemplate.value.id)
|
|
||||||
ElMessage.success('默认模板已更新')
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error(error instanceof Error ? error.message : '设置默认模板失败')
|
|
||||||
} finally {
|
|
||||||
templateSavingDefault.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function removeCurrentTemplate() {
|
|
||||||
if (!currentConvertTemplate.value) {
|
|
||||||
ElMessage.warning('请先选择模板')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (currentConvertTemplate.value.builtIn) {
|
|
||||||
ElMessage.warning('内置模板不允许删除')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
templateDeleting.value = true
|
|
||||||
await deleteConvertTemplate(currentConvertTemplate.value.templateCode || currentConvertTemplate.value.id)
|
|
||||||
const deletedTemplateId = currentConvertTemplate.value.id
|
|
||||||
await loadConvertTemplates()
|
|
||||||
if (convertTemplateId.value === deletedTemplateId) {
|
|
||||||
convertTemplateId.value = convertTemplates.value[0]?.id || ''
|
|
||||||
}
|
|
||||||
ElMessage.success('模板已删除')
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error(error instanceof Error ? error.message : '删除模板失败')
|
|
||||||
} finally {
|
|
||||||
templateDeleting.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function saveTemplateFromUrl(url: string, fallbackFilename: string, bridgeMethod?: 'save_template_xlsx' | 'save_template_zip') {
|
|
||||||
const api = getPywebviewApi()
|
|
||||||
|
|
||||||
if (bridgeMethod && api?.[bridgeMethod]) {
|
|
||||||
const result = await api[bridgeMethod]!()
|
|
||||||
if (result.success) {
|
|
||||||
ElMessage.success(`已保存:${result.path || fallbackFilename}`)
|
|
||||||
} else if (result.error && result.error !== '用户取消') {
|
|
||||||
ElMessage.error(result.error)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await saveUrlWithProgress(url, fallbackFilename)
|
|
||||||
if (result.success) {
|
|
||||||
ElMessage.success(`已保存:${result.path || fallbackFilename}`)
|
|
||||||
} else if (result.error && result.error !== '用户取消') {
|
|
||||||
ElMessage.error(result.error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function downloadTemplateXlsx() {
|
|
||||||
await saveTemplateFromUrl(getBrandTemplateXlsxUrl(), '品牌文档格式_模板.xlsx', 'save_template_xlsx')
|
|
||||||
}
|
|
||||||
|
|
||||||
async function downloadTemplateZip() {
|
|
||||||
await saveTemplateFromUrl(getBrandTemplateZipUrl(), '模板2-以文件夹方式上传.zip', 'save_template_zip')
|
|
||||||
}
|
|
||||||
|
|
||||||
async function submitConvertRun() {
|
async function submitConvertRun() {
|
||||||
if (!convertUploadedFiles.value.length) {
|
if (!convertUploadedFiles.value.length) {
|
||||||
ElMessage.warning('请先选择待转换 Excel 文件或文件夹')
|
ElMessage.warning('请先选择待转换 Excel 文件或文件夹')
|
||||||
|
|||||||
@@ -119,7 +119,6 @@ import {
|
|||||||
deleteDeleteBrandHistory,
|
deleteDeleteBrandHistory,
|
||||||
getDeleteBrandHistory,
|
getDeleteBrandHistory,
|
||||||
getDeleteBrandResultDownloadUrl,
|
getDeleteBrandResultDownloadUrl,
|
||||||
getDeleteBrandTaskDetails,
|
|
||||||
getDeleteBrandTaskProgress,
|
getDeleteBrandTaskProgress,
|
||||||
getDeleteBrandTaskDownloadUrl,
|
getDeleteBrandTaskDownloadUrl,
|
||||||
runDeleteBrand,
|
runDeleteBrand,
|
||||||
|
|||||||
@@ -213,7 +213,6 @@ import ModuleTemplateDownload from '@/shared/components/ModuleTemplateDownload.v
|
|||||||
import ZiniaoVersionSetting from '@/shared/components/ZiniaoVersionSetting.vue'
|
import ZiniaoVersionSetting from '@/shared/components/ZiniaoVersionSetting.vue'
|
||||||
import TaskCenterPanel from '@/shared/components/tasks/TaskCenterPanel.vue'
|
import TaskCenterPanel from '@/shared/components/tasks/TaskCenterPanel.vue'
|
||||||
import type { TaskItemView, TaskStatCard } from '@/shared/components/tasks/types'
|
import type { TaskItemView, TaskStatCard } from '@/shared/components/tasks/types'
|
||||||
import { LISTING_FILTER_OPTIONS, type ListingFilterValue } from '@/pages/brand/components/listingFilters'
|
|
||||||
import { expandBrandFolderRecursive } from '@/shared/api/brand'
|
import { expandBrandFolderRecursive } from '@/shared/api/brand'
|
||||||
import { getPywebviewApi, type PywebviewApi, type UploadedJavaFile } from '@/shared/bridges/pywebview'
|
import { getPywebviewApi, type PywebviewApi, type UploadedJavaFile } from '@/shared/bridges/pywebview'
|
||||||
import { getTaskPollIntervalMs } from '@/shared/task-progress-config'
|
import { getTaskPollIntervalMs } from '@/shared/task-progress-config'
|
||||||
@@ -242,7 +241,6 @@ import {
|
|||||||
getPriceTrackLoopRun,
|
getPriceTrackLoopRun,
|
||||||
getPriceTrackResultDownloadUrl,
|
getPriceTrackResultDownloadUrl,
|
||||||
getPriceTrackTaskProgressBatch,
|
getPriceTrackTaskProgressBatch,
|
||||||
getPriceTrackTasksBatch,
|
|
||||||
getTaskSkipPriceAsinsPaginated,
|
getTaskSkipPriceAsinsPaginated,
|
||||||
listPriceTrackCandidates,
|
listPriceTrackCandidates,
|
||||||
matchPriceTrackShops,
|
matchPriceTrackShops,
|
||||||
@@ -942,88 +940,6 @@ async function removeMatchedRow(row: PriceTrackShopQueueItem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function pushToPythonQueueLegacy() {
|
|
||||||
if (!hasValidMode.value) {
|
|
||||||
ElMessage.warning('请至少选择一个跟价模式')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (asinModeEnabled.value && !asinFiles.value.length) {
|
|
||||||
ElMessage.warning('请先选择 ASIN 文件')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const api = getPywebviewApi()
|
|
||||||
if (!api?.enqueue_json) {
|
|
||||||
ElMessage.error('当前环境未启用 pywebview enqueue_json')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const matchedRows = matchedItems.value.filter((i) => i.matched)
|
|
||||||
if (!matchedRows.length) {
|
|
||||||
ElMessage.warning('无可用匹配店铺')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pushing.value = true
|
|
||||||
queuePayloadText.value = ''
|
|
||||||
try {
|
|
||||||
// 1. 先调用 Java API 创建任务(落库,含 skip ASIN)
|
|
||||||
const taskReq = {
|
|
||||||
userId: 0, // 会被 java-modules 自动填充
|
|
||||||
statusMode: statusModeEnabled.value,
|
|
||||||
asinMode: asinModeEnabled.value,
|
|
||||||
items: matchedRows as unknown as Record<string, unknown>[],
|
|
||||||
asinFiles: resolveAsinRequestPaths(),
|
|
||||||
countryCodes: resolveCountryCodesForRequest(),
|
|
||||||
}
|
|
||||||
const taskVo = await createPriceTrackTask(taskReq)
|
|
||||||
taskSnapshots.value = {
|
|
||||||
...taskSnapshots.value,
|
|
||||||
[taskVo.taskId]: {
|
|
||||||
task: { id: taskVo.taskId, status: 'RUNNING' },
|
|
||||||
items: taskVo.items,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
taskDetails.value = {
|
|
||||||
...taskDetails.value,
|
|
||||||
[taskVo.taskId]: 'RUNNING',
|
|
||||||
}
|
|
||||||
saveTaskSnapshotsToStorage()
|
|
||||||
saveTaskDetailsToStorage()
|
|
||||||
|
|
||||||
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,
|
|
||||||
ziniao_version: ziniaoVersion.value,
|
|
||||||
shop_name: (firstRow.shopName || '').trim(),
|
|
||||||
shopName: (firstRow.shopName || '').trim(),
|
|
||||||
companyName: firstRow.companyName || '',
|
|
||||||
shopMallName: firstRow.shopMallName || '',
|
|
||||||
country_codes: resolveCountryCodesForRequest(),
|
|
||||||
mode: priceTrackModeForAppClient(),
|
|
||||||
asin_rows_by_country: asinRowsByCountry,
|
|
||||||
minimum_price_by_country_and_asin: minimumPriceByCountryAndAsin,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
queuePayloadText.value = JSON.stringify(queuePayload, null, 2)
|
|
||||||
|
|
||||||
await enqueueCreatedTask(api, taskVo.taskId, queuePayload)
|
|
||||||
queuePushResult.value = `任务 ${taskVo.taskId} 已入队,等待执行完成...`
|
|
||||||
addPollingTask(taskVo.taskId)
|
|
||||||
scheduleNextPoll(true)
|
|
||||||
ElMessage.success('已启动任务')
|
|
||||||
} catch (e) {
|
|
||||||
queuePushResult.value = e instanceof Error ? e.message : '推送异常'
|
|
||||||
ElMessage.error(queuePushResult.value)
|
|
||||||
} finally {
|
|
||||||
pushing.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========== 任务状态轮询 ==========
|
// ========== 任务状态轮询 ==========
|
||||||
async function buildQueuePayload(taskVo: PriceTrackCreateTaskVo, row: PriceTrackShopQueueItem) {
|
async function buildQueuePayload(taskVo: PriceTrackCreateTaskVo, row: PriceTrackShopQueueItem) {
|
||||||
const shopName = (row.shopName || '').trim()
|
const shopName = (row.shopName || '').trim()
|
||||||
@@ -1155,11 +1071,6 @@ async function waitForTaskTerminal(taskId: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function pushToPythonQueue() {
|
|
||||||
autoQueueEnabled.value = true
|
|
||||||
await processMatchedQueue()
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextMatchedQueueItem() {
|
function nextMatchedQueueItem() {
|
||||||
return matchedItems.value.find((item) => item.matched)
|
return matchedItems.value.find((item) => item.matched)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,7 +159,6 @@ import {
|
|||||||
getProductRiskHistory,
|
getProductRiskHistory,
|
||||||
getProductRiskResultDownloadUrl,
|
getProductRiskResultDownloadUrl,
|
||||||
getProductRiskTaskProgressBatch,
|
getProductRiskTaskProgressBatch,
|
||||||
getProductRiskTasksBatch,
|
|
||||||
listProductRiskCandidates,
|
listProductRiskCandidates,
|
||||||
matchProductRiskShops,
|
matchProductRiskShops,
|
||||||
putProductRiskCountryPreference,
|
putProductRiskCountryPreference,
|
||||||
|
|||||||
@@ -452,18 +452,6 @@ function toPublishTaskView(detail: PublishTaskDetailVo): TaskItemView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const summary = computed(() => {
|
|
||||||
const files = visibleTasks.value.flatMap((detail) => detail.files || [])
|
|
||||||
const successCount = files.filter((file) => ['SUCCESS', 'COMPLETED'].includes(normalizeStatus(file.status))).length
|
|
||||||
const failedCount = files.filter((file) => ['FAILED', 'CANCELLED'].includes(normalizeStatus(file.status))).length
|
|
||||||
return {
|
|
||||||
total: files.length,
|
|
||||||
completed: successCount + failedCount,
|
|
||||||
successCount,
|
|
||||||
failedCount,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const operationHint = computed(() => {
|
const operationHint = computed(() => {
|
||||||
if (uploading.value) return '正在逐个上传文件到后端...'
|
if (uploading.value) return '正在逐个上传文件到后端...'
|
||||||
if (parsing.value) return '正在解析 Excel、匹配店铺并创建批次...'
|
if (parsing.value) return '正在解析 Excel、匹配店铺并创建批次...'
|
||||||
|
|||||||
@@ -618,13 +618,6 @@ function isRecordMissingError(error: unknown) {
|
|||||||
return /记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(message);
|
return /记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeMatchedRowLocally(row: QueryAsinShopQueueItem) {
|
|
||||||
matchedItems.value = matchedItems.value.filter(
|
|
||||||
(item) => rowKeyForMatch(item) !== rowKeyForMatch(row),
|
|
||||||
);
|
|
||||||
saveMatchedItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeHistoryItemLocally(item: QueryAsinHistoryItem) {
|
function removeHistoryItemLocally(item: QueryAsinHistoryItem) {
|
||||||
historyItems.value = historyItems.value.filter((row) => {
|
historyItems.value = historyItems.value.filter((row) => {
|
||||||
if (item.resultId != null && row.resultId === item.resultId) return false;
|
if (item.resultId != null && row.resultId === item.resultId) return false;
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ import TaskCenterPanel from '@/shared/components/tasks/TaskCenterPanel.vue'
|
|||||||
import type { TaskItemView, TaskStatCard } from '@/shared/components/tasks/types'
|
import type { TaskItemView, TaskStatCard } from '@/shared/components/tasks/types'
|
||||||
import ZiniaoVersionSetting from '@/shared/components/ZiniaoVersionSetting.vue'
|
import ZiniaoVersionSetting from '@/shared/components/ZiniaoVersionSetting.vue'
|
||||||
import { LISTING_FILTER_OPTIONS, type ListingFilterValue } from '@/pages/brand/components/listingFilters'
|
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 { activateShopMatchTask, addShopMatchCandidate, createShopMatchTask, deleteShopMatchCandidate, deleteShopMatchHistory, deleteShopMatchTask, getShopMatchCountryPreference, getShopMatchDashboard, getShopMatchHistory, getShopMatchResultDownloadUrl, getShopMatchTaskProgressBatch, 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 { getPywebviewApi } from '@/shared/bridges/pywebview'
|
||||||
import { getTaskPollIntervalMs } from '@/shared/task-progress-config'
|
import { getTaskPollIntervalMs } from '@/shared/task-progress-config'
|
||||||
import { createCategorizedTimers } from '@/shared/utils/categorized-timers'
|
import { createCategorizedTimers } from '@/shared/utils/categorized-timers'
|
||||||
|
|||||||
@@ -134,7 +134,6 @@ import {
|
|||||||
type SimilarAsinParseVo,
|
type SimilarAsinParseVo,
|
||||||
type UploadedFileRef,
|
type UploadedFileRef,
|
||||||
type UploadFileVo,
|
type UploadFileVo,
|
||||||
uploadTempFileToJava,
|
|
||||||
} from '@/shared/api/java-modules'
|
} from '@/shared/api/java-modules'
|
||||||
import { expandBrandFolderRecursive, type BrandExpandFolderItem } from '@/shared/api/brand'
|
import { expandBrandFolderRecursive, type BrandExpandFolderItem } from '@/shared/api/brand'
|
||||||
import { getPywebviewApi, type ProxyMode } from '@/shared/bridges/pywebview'
|
import { getPywebviewApi, type ProxyMode } from '@/shared/bridges/pywebview'
|
||||||
|
|||||||
@@ -288,15 +288,6 @@ function statusText(status?: number | string) {
|
|||||||
return String(status ?? '未知')
|
return String(status ?? '未知')
|
||||||
}
|
}
|
||||||
|
|
||||||
function statusClass(status?: number | string) {
|
|
||||||
const numeric = Number(status)
|
|
||||||
if (numeric === 1 || String(status).toLowerCase() === 'running') return 'running'
|
|
||||||
if (numeric === 2 || ['success', 'completed', 'done'].includes(String(status).toLowerCase())) return 'success'
|
|
||||||
if (numeric === 3 || ['failed', 'error'].includes(String(status).toLowerCase())) return 'failed'
|
|
||||||
if (['cancelled', 'stopped'].includes(String(status).toLowerCase())) return 'cancelled'
|
|
||||||
return 'pending'
|
|
||||||
}
|
|
||||||
|
|
||||||
function isBusy(status?: number | string) {
|
function isBusy(status?: number | string) {
|
||||||
const numeric = Number(status)
|
const numeric = Number(status)
|
||||||
return numeric === 0 || numeric === 1 || String(status).toLowerCase() === 'pending' || String(status).toLowerCase() === 'running'
|
return numeric === 0 || numeric === 1 || String(status).toLowerCase() === 'pending' || String(status).toLowerCase() === 'running'
|
||||||
@@ -320,10 +311,6 @@ function latestMessage(item: VariantEntry) {
|
|||||||
return (raw || '').trim() || '等待后台处理…'
|
return (raw || '').trim() || '等待后台处理…'
|
||||||
}
|
}
|
||||||
|
|
||||||
function taskMeta(item: VariantEntry) {
|
|
||||||
return { source: item.meta?.source || '' }
|
|
||||||
}
|
|
||||||
|
|
||||||
function resultFiles(item?: VariantEntry) {
|
function resultFiles(item?: VariantEntry) {
|
||||||
return toArray(item?.file_url)
|
return toArray(item?.file_url)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -762,13 +762,6 @@ function isRecordMissingError(error: unknown) {
|
|||||||
return /记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(message);
|
return /记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeMatchedRowLocally(row: WithdrawShopQueueItem) {
|
|
||||||
matchedItems.value = matchedItems.value.filter(
|
|
||||||
(item) => rowKeyForMatch(item) !== rowKeyForMatch(row),
|
|
||||||
);
|
|
||||||
saveMatchedItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeHistoryItemLocally(item: WithdrawHistoryItem) {
|
function removeHistoryItemLocally(item: WithdrawHistoryItem) {
|
||||||
historyItems.value = historyItems.value.filter((row) => {
|
historyItems.value = historyItems.value.filter((row) => {
|
||||||
if (item.resultId != null && row.resultId === item.resultId) return false;
|
if (item.resultId != null && row.resultId === item.resultId) return false;
|
||||||
|
|||||||
@@ -164,13 +164,6 @@ function toggleUpdatePanel() {
|
|||||||
updatePanel.value = !updatePanel.value
|
updatePanel.value = !updatePanel.value
|
||||||
}
|
}
|
||||||
|
|
||||||
function showTip(message: string) {
|
|
||||||
toastText.value = message
|
|
||||||
window.setTimeout(() => {
|
|
||||||
if (toastText.value === message) toastText.value = ''
|
|
||||||
}, 2600)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchVersion() {
|
async function fetchVersion() {
|
||||||
try {
|
try {
|
||||||
const resp = await window.fetch('/api/version', { credentials: 'same-origin' })
|
const resp = await window.fetch('/api/version', { credentials: 'same-origin' })
|
||||||
|
|||||||
@@ -91,7 +91,7 @@
|
|||||||
:source-url="currentWorkspace.sceneAsset.sourceUrl" :loading="currentWorkspace.sceneAsset.uploading"
|
:source-url="currentWorkspace.sceneAsset.sourceUrl" :loading="currentWorkspace.sceneAsset.uploading"
|
||||||
allow-url compact action-label="上传场景图" selected-label="场景图" url-label="场景图链接" url-placeholder="也可以粘贴场景图链接"
|
allow-url compact action-label="上传场景图" selected-label="场景图" url-label="场景图链接" url-placeholder="也可以粘贴场景图链接"
|
||||||
@select="(file) => setAsset(activeTab, 'sceneAsset', file)"
|
@select="(file) => setAsset(activeTab, 'sceneAsset', file)"
|
||||||
@url-change="(url) => setAssetUrl(activeTab, 'sceneAsset', url, 'image/*')" preview-clickable
|
@url-change="(url) => setAssetUrl(activeTab, 'sceneAsset', url)" preview-clickable
|
||||||
@preview="openImagePreview" @clear="clearAsset(activeTab, 'sceneAsset')" />
|
@preview="openImagePreview" @clear="clearAsset(activeTab, 'sceneAsset')" />
|
||||||
</AiSectionCard>
|
</AiSectionCard>
|
||||||
</div>
|
</div>
|
||||||
@@ -190,7 +190,7 @@
|
|||||||
:source-url="currentWorkspace.modelAsset.sourceUrl" :loading="currentWorkspace.modelAsset.uploading"
|
:source-url="currentWorkspace.modelAsset.sourceUrl" :loading="currentWorkspace.modelAsset.uploading"
|
||||||
allow-url compact preview-clickable action-label="上传模特图" selected-label="模特图" url-label="模特图链接"
|
allow-url compact preview-clickable action-label="上传模特图" selected-label="模特图" url-label="模特图链接"
|
||||||
url-placeholder="也可以粘贴模特图链接" @select="(file) => setAsset(activeTab, 'modelAsset', file)"
|
url-placeholder="也可以粘贴模特图链接" @select="(file) => setAsset(activeTab, 'modelAsset', file)"
|
||||||
@url-change="(url) => setAssetUrl(activeTab, 'modelAsset', url, 'image/*')" @preview="openImagePreview"
|
@url-change="(url) => setAssetUrl(activeTab, 'modelAsset', url)" @preview="openImagePreview"
|
||||||
@clear="clearAsset(activeTab, 'modelAsset')" />
|
@clear="clearAsset(activeTab, 'modelAsset')" />
|
||||||
</AiSectionCard>
|
</AiSectionCard>
|
||||||
|
|
||||||
@@ -277,7 +277,7 @@
|
|||||||
:source-url="currentWorkspace.speechAsset.sourceUrl" :loading="currentWorkspace.speechAsset.uploading"
|
:source-url="currentWorkspace.speechAsset.sourceUrl" :loading="currentWorkspace.speechAsset.uploading"
|
||||||
allow-url compact action-label="上传背景音乐" selected-label="背景音乐" url-label="背景音乐链接"
|
allow-url compact action-label="上传背景音乐" selected-label="背景音乐" url-label="背景音乐链接"
|
||||||
@select="(file) => setAsset(activeTab, 'speechAsset', file)"
|
@select="(file) => setAsset(activeTab, 'speechAsset', file)"
|
||||||
@url-change="(url) => setAssetUrl(activeTab, 'speechAsset', url, 'audio/*')"
|
@url-change="(url) => setAssetUrl(activeTab, 'speechAsset', url)"
|
||||||
@clear="clearAsset(activeTab, 'speechAsset')" />
|
@clear="clearAsset(activeTab, 'speechAsset')" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -786,7 +786,7 @@ function resolvePreviewKindFromMediaType(mediaType: string): PreviewKind {
|
|||||||
return 'file'
|
return 'file'
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveMediaTypeFromUrl(url: string, accept = ''): MediaType {
|
function resolveMediaTypeFromUrl(url: string): MediaType {
|
||||||
const cleanUrl = url.split('?')[0]?.toLowerCase() || ''
|
const cleanUrl = url.split('?')[0]?.toLowerCase() || ''
|
||||||
if (/\.(png|jpe?g|webp|gif|bmp|svg)$/.test(cleanUrl)) return 'image'
|
if (/\.(png|jpe?g|webp|gif|bmp|svg)$/.test(cleanUrl)) return 'image'
|
||||||
if (/\.(mp4|mov|webm|m4v|ogg|avi|mkv)$/.test(cleanUrl)) return 'video'
|
if (/\.(mp4|mov|webm|m4v|ogg|avi|mkv)$/.test(cleanUrl)) return 'video'
|
||||||
@@ -794,10 +794,10 @@ function resolveMediaTypeFromUrl(url: string, accept = ''): MediaType {
|
|||||||
return 'file'
|
return 'file'
|
||||||
}
|
}
|
||||||
|
|
||||||
function setAssetUrl(tab: WorkspaceTab, assetKey: AssetKey, url: string, accept = '') {
|
function setAssetUrl(tab: WorkspaceTab, assetKey: AssetKey, url: string) {
|
||||||
const target = workspaces[tab][assetKey]
|
const target = workspaces[tab][assetKey]
|
||||||
const normalizedUrl = (url || '').trim()
|
const normalizedUrl = (url || '').trim()
|
||||||
const mediaType = resolveMediaTypeFromUrl(normalizedUrl, accept)
|
const mediaType = resolveMediaTypeFromUrl(normalizedUrl)
|
||||||
target.sourceUrl = normalizedUrl
|
target.sourceUrl = normalizedUrl
|
||||||
target.previewUrl = normalizedUrl
|
target.previewUrl = normalizedUrl
|
||||||
target.fileName = normalizedUrl ? '在线素材' : ''
|
target.fileName = normalizedUrl ? '在线素材' : ''
|
||||||
@@ -855,7 +855,7 @@ function setProductAssetUrl(tab: WorkspaceTab, index: number, url: string) {
|
|||||||
target.sourceUrl = normalizedUrl
|
target.sourceUrl = normalizedUrl
|
||||||
target.previewUrl = normalizedUrl
|
target.previewUrl = normalizedUrl
|
||||||
target.fileName = normalizedUrl ? '在线素材' : ''
|
target.fileName = normalizedUrl ? '在线素材' : ''
|
||||||
target.mediaType = resolveMediaTypeFromUrl(normalizedUrl, 'image/*')
|
target.mediaType = resolveMediaTypeFromUrl(normalizedUrl)
|
||||||
target.previewKind = resolvePreviewKindFromMediaType(target.mediaType)
|
target.previewKind = resolvePreviewKindFromMediaType(target.mediaType)
|
||||||
scheduleDeliveryGridLayout()
|
scheduleDeliveryGridLayout()
|
||||||
}
|
}
|
||||||
@@ -1517,26 +1517,6 @@ function findMediaFileUrl(value: unknown) {
|
|||||||
]) || findUrlMatching(value, isMediaFileUrl)
|
]) || findUrlMatching(value, isMediaFileUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveWorkflowStatus(value: unknown) {
|
|
||||||
return (findTextByKeys(value, [
|
|
||||||
'execute_status',
|
|
||||||
'executeStatus',
|
|
||||||
'workflow_status',
|
|
||||||
'workflowStatus',
|
|
||||||
'status',
|
|
||||||
]) || '').toUpperCase()
|
|
||||||
}
|
|
||||||
|
|
||||||
function isTerminalWorkflowStatus(status: string) {
|
|
||||||
const normalized = (status || '').toUpperCase()
|
|
||||||
return ['SUCCESS', 'SUCCEEDED', 'COMPLETED', 'DONE', 'FINISHED', 'FAILED', 'FAIL', 'ERROR', 'CANCELED', 'CANCELLED'].includes(normalized)
|
|
||||||
}
|
|
||||||
|
|
||||||
function isFailedWorkflowStatus(status: string) {
|
|
||||||
const normalized = (status || '').toUpperCase()
|
|
||||||
return ['FAILED', 'FAIL', 'ERROR', 'CANCELED', 'CANCELLED'].includes(normalized)
|
|
||||||
}
|
|
||||||
|
|
||||||
function findTextByKeys(value: unknown, keys: string[]): string {
|
function findTextByKeys(value: unknown, keys: string[]): string {
|
||||||
if (!value) return ''
|
if (!value) return ''
|
||||||
const normalizedKeys = keys.map((key) => key.toLowerCase())
|
const normalizedKeys = keys.map((key) => key.toLowerCase())
|
||||||
@@ -1751,7 +1731,7 @@ async function synthesizeVoice() {
|
|||||||
const result = await waitForImageVideoTask(ticket)
|
const result = await waitForImageVideoTask(ticket)
|
||||||
const audioUrl = findMediaFileUrl(result)
|
const audioUrl = findMediaFileUrl(result)
|
||||||
if (audioUrl) {
|
if (audioUrl) {
|
||||||
setAssetUrl(activeTab.value, 'speechAsset', audioUrl, 'audio/*')
|
setAssetUrl(activeTab.value, 'speechAsset', audioUrl)
|
||||||
setVoiceStatus('语音合成完成,已写入最终配音文件', 'success')
|
setVoiceStatus('语音合成完成,已写入最终配音文件', 'success')
|
||||||
ElMessage.success('语音合成完成,已写入口播音频链接')
|
ElMessage.success('语音合成完成,已写入口播音频链接')
|
||||||
} else {
|
} else {
|
||||||
@@ -1794,7 +1774,7 @@ async function setVoiceCloneAsset(file: File) {
|
|||||||
|
|
||||||
function setVoiceCloneUrl(url: string) {
|
function setVoiceCloneUrl(url: string) {
|
||||||
const normalizedUrl = (url || '').trim()
|
const normalizedUrl = (url || '').trim()
|
||||||
const mediaType = resolveMediaTypeFromUrl(normalizedUrl, 'audio/*,video/*')
|
const mediaType = resolveMediaTypeFromUrl(normalizedUrl)
|
||||||
voiceCloneAsset.sourceUrl = normalizedUrl
|
voiceCloneAsset.sourceUrl = normalizedUrl
|
||||||
voiceCloneAsset.previewUrl = normalizedUrl
|
voiceCloneAsset.previewUrl = normalizedUrl
|
||||||
voiceCloneAsset.fileName = normalizedUrl ? '在线克隆素材' : ''
|
voiceCloneAsset.fileName = normalizedUrl ? '在线克隆素材' : ''
|
||||||
|
|||||||
@@ -659,10 +659,6 @@ function refreshModalFooter() {
|
|||||||
modalShow.workspaceRegenerate = src === 'workspace'
|
modalShow.workspaceRegenerate = src === 'workspace'
|
||||||
}
|
}
|
||||||
|
|
||||||
function imageModalVisible(img: string) {
|
|
||||||
return img.startsWith('data:') || img.startsWith('http')
|
|
||||||
}
|
|
||||||
|
|
||||||
function openImageModal(images: string[], index: number, opts?: ModalSourceOpts) {
|
function openImageModal(images: string[], index: number, opts?: ModalSourceOpts) {
|
||||||
const o = opts || {}
|
const o = opts || {}
|
||||||
imageModalImages.value = (Array.isArray(images) ? images : [images]).map(String)
|
imageModalImages.value = (Array.isArray(images) ? images : [images]).map(String)
|
||||||
@@ -765,10 +761,6 @@ function triggerBlobDownload(blob: Blob, filename: string) {
|
|||||||
URL.revokeObjectURL(blobUrl)
|
URL.revokeObjectURL(blobUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function modalDownloadCurrent() {
|
|
||||||
const src = imageModalImages.value[imageModalIndex.value]
|
|
||||||
await downloadImage(src, `原图_${imageModalIndex.value + 1}.png`)
|
|
||||||
}
|
|
||||||
async function modalBatchDownload() {
|
async function modalBatchDownload() {
|
||||||
for (let i = 0; i < imageModalImages.value.length; i++) {
|
for (let i = 0; i < imageModalImages.value.length; i++) {
|
||||||
await downloadImage(imageModalImages.value[i], `image_${i + 1}.png`)
|
await downloadImage(imageModalImages.value[i], `image_${i + 1}.png`)
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ const routes = [
|
|||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(),
|
history: createWebHistory(),
|
||||||
routes,
|
routes,
|
||||||
scrollBehavior(to, _from, savedPosition) {
|
scrollBehavior(_to, _from, savedPosition) {
|
||||||
// 返回工具台的 #group-xxx 锚点由组件 onMounted 处理;普通滚动回顶部
|
// 返回工具台的 #group-xxx 锚点由组件 onMounted 处理;普通滚动回顶部
|
||||||
if (savedPosition) return savedPosition
|
if (savedPosition) return savedPosition
|
||||||
return { top: 0 }
|
return { top: 0 }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { get, post, put, del, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
import { get, post, put, del, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
||||||
import { buildJavaUrl, JAVA_API_PREFIX } from '../../url.ts'
|
import { JAVA_API_PREFIX } from '../../url.ts'
|
||||||
import { getCurrentUserId } from '../../user.ts'
|
import { getCurrentUserId } from '../../user.ts'
|
||||||
import { getTaskProgressCacheTtlMs, getTaskProgressTimeoutMs } from '../../../task-progress-config.ts'
|
import { getTaskProgressCacheTtlMs, getTaskProgressTimeoutMs } from '../../../task-progress-config.ts'
|
||||||
import { createTaskProgressRequestCache } from '../../../task-progress-request-cache.ts'
|
import { createTaskProgressRequestCache } from '../../../task-progress-request-cache.ts'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { get, post, put, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
import { get, post, put, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
||||||
import { buildJavaUrl, JAVA_API_PREFIX } from '../../url.ts'
|
import { JAVA_API_PREFIX } from '../../url.ts'
|
||||||
import { getCurrentUserId } from '../../user.ts'
|
import { getCurrentUserId } from '../../user.ts'
|
||||||
|
|
||||||
export interface ImageVideoDouyinCopyVo {
|
export interface ImageVideoDouyinCopyVo {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { get, post, put, del, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
import { get, post, put, del, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
||||||
import { buildJavaUrl, JAVA_API_PREFIX } from '../../url.ts'
|
import { JAVA_API_PREFIX } from '../../url.ts'
|
||||||
import { getCurrentUserId } from '../../user.ts'
|
import { getCurrentUserId } from '../../user.ts'
|
||||||
import { getJavaDownloadUrl } from '../../download-url.ts'
|
import { getJavaDownloadUrl } from '../../download-url.ts'
|
||||||
import { getTaskProgressCacheTtlMs, getTaskProgressTimeoutMs } from '../../../task-progress-config.ts'
|
import { getTaskProgressCacheTtlMs, getTaskProgressTimeoutMs } from '../../../task-progress-config.ts'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { get, post, put, del, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
import { get, post, put, del, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
||||||
import { buildJavaUrl, JAVA_API_PREFIX } from '../../url.ts'
|
import { JAVA_API_PREFIX } from '../../url.ts'
|
||||||
import { getCurrentUserId } from '../../user.ts'
|
import { getCurrentUserId } from '../../user.ts'
|
||||||
import { getJavaDownloadUrl } from '../../download-url.ts'
|
import { getJavaDownloadUrl } from '../../download-url.ts'
|
||||||
import { getTaskProgressCacheTtlMs, getTaskProgressTimeoutMs } from '../../../task-progress-config.ts'
|
import { getTaskProgressCacheTtlMs, getTaskProgressTimeoutMs } from '../../../task-progress-config.ts'
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { get, post, put, del, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
import { get, post, put, del, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
||||||
import { buildJavaUrl, JAVA_API_PREFIX } from '../../url.ts'
|
import { JAVA_API_PREFIX } from '../../url.ts'
|
||||||
import { getCurrentUserId } from '../../user.ts'
|
import { getCurrentUserId } from '../../user.ts'
|
||||||
import { getJavaDownloadUrl } from '../../download-url.ts'
|
import { getJavaDownloadUrl } from '../../download-url.ts'
|
||||||
import { getTaskProgressCacheTtlMs, getTaskProgressTimeoutMs } from '../../../task-progress-config.ts'
|
import { getTaskProgressCacheTtlMs, getTaskProgressTimeoutMs } from '../../../task-progress-config.ts'
|
||||||
import { createTaskProgressRequestCache } from '../../../task-progress-request-cache.ts'
|
import { createTaskProgressRequestCache } from '../../../task-progress-request-cache.ts'
|
||||||
import { API_ENDPOINTS } from '../../endpoints.ts'
|
|
||||||
import type { QueryAsinCountryAsins } from './query-asin.ts'
|
import type { QueryAsinCountryAsins } from './query-asin.ts'
|
||||||
|
|
||||||
/** 商品风险处理:备选店铺与匹配相关数据结构。 */
|
/** 商品风险处理:备选店铺与匹配相关数据结构。 */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { get, post, del, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
import { get, post, del, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
||||||
import { buildJavaUrl, JAVA_API_PREFIX } from '../../url.ts'
|
import { JAVA_API_PREFIX } from '../../url.ts'
|
||||||
import { getCurrentUserId } from '../../user.ts'
|
import { getCurrentUserId } from '../../user.ts'
|
||||||
import { getJavaDownloadUrl } from '../../download-url.ts'
|
import { getJavaDownloadUrl } from '../../download-url.ts'
|
||||||
import { getTaskProgressCacheTtlMs, getTaskProgressTimeoutMs } from '../../../task-progress-config.ts'
|
import { getTaskProgressCacheTtlMs, getTaskProgressTimeoutMs } from '../../../task-progress-config.ts'
|
||||||
|
|||||||
@@ -6,18 +6,9 @@ import {
|
|||||||
getTaskForegroundRefreshDelayMs,
|
getTaskForegroundRefreshDelayMs,
|
||||||
} from '../task-progress-config.ts'
|
} from '../task-progress-config.ts'
|
||||||
import { createCategorizedTimers } from '../utils/categorized-timers.ts'
|
import { createCategorizedTimers } from '../utils/categorized-timers.ts'
|
||||||
import {
|
import { createTaskPollingBaseline, type TaskPollingBaseline } from '../task-polling-baseline.ts'
|
||||||
createTaskPollingBaseline,
|
import type { ProgressResponseCache } from '../progress-response-cache.ts'
|
||||||
type TaskPollingBaseline,
|
import type { TaskPollingCoordinator } from '../task-polling-coordinator.ts'
|
||||||
} from '../task-polling-baseline.ts'
|
|
||||||
import {
|
|
||||||
createProgressResponseCache,
|
|
||||||
type ProgressResponseCache,
|
|
||||||
} from '../progress-response-cache.ts'
|
|
||||||
import {
|
|
||||||
createTaskPollingCoordinator,
|
|
||||||
type TaskPollingCoordinator,
|
|
||||||
} from '../task-polling-coordinator.ts'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用任务进度轮询组合式函数。
|
* 通用任务进度轮询组合式函数。
|
||||||
@@ -86,7 +77,7 @@ export interface TaskProgressLoopOptions<TDetail> {
|
|||||||
coordinator?: TaskPollingCoordinator
|
coordinator?: TaskPollingCoordinator
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TaskProgressLoopHandle<TDetail> {
|
export interface TaskProgressLoopHandle {
|
||||||
taskIds: Ref<number[]>
|
taskIds: Ref<number[]>
|
||||||
taskStatuses: Ref<Record<number, string>>
|
taskStatuses: Ref<Record<number, string>>
|
||||||
inFlight: Ref<boolean>
|
inFlight: Ref<boolean>
|
||||||
@@ -135,7 +126,7 @@ function writeIdsToStorage(key: string | undefined, ids: number[]) {
|
|||||||
|
|
||||||
export function useTaskProgressLoop<TDetail>(
|
export function useTaskProgressLoop<TDetail>(
|
||||||
options: TaskProgressLoopOptions<TDetail>,
|
options: TaskProgressLoopOptions<TDetail>,
|
||||||
): TaskProgressLoopHandle<TDetail> {
|
): TaskProgressLoopHandle {
|
||||||
const timers = createCategorizedTimers(`task-progress-loop:${options.scope}`)
|
const timers = createCategorizedTimers(`task-progress-loop:${options.scope}`)
|
||||||
const isTerminal = options.isTerminal ?? DEFAULT_TERMINAL
|
const isTerminal = options.isTerminal ?? DEFAULT_TERMINAL
|
||||||
const intervalMs = options.getIntervalMs ?? getTaskPollIntervalMs
|
const intervalMs = options.getIntervalMs ?? getTaskPollIntervalMs
|
||||||
|
|||||||
@@ -12,7 +12,3 @@ export function resolvePageHref(rawHref?: string): string {
|
|||||||
return rawHref.replace(/^\/new_web_source\/(.+)\.html$/, '/$1')
|
return rawHref.replace(/^\/new_web_source\/(.+)\.html$/, '/$1')
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 兼容旧引用:SPA 下生产/开发路径一致,恒为 false(页面不再按路径区分桌面/Web) */
|
|
||||||
export function isDesktopClientPage(): boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export function createProgressResponseCache<V>(options: ProgressResponseCacheOpt
|
|||||||
return removed
|
return removed
|
||||||
}
|
}
|
||||||
|
|
||||||
function evictIfNeeded(at: number) {
|
function evictIfNeeded(_at: number) {
|
||||||
while (map.size > maxEntries) {
|
while (map.size > maxEntries) {
|
||||||
const oldest = map.keys().next().value as number | undefined
|
const oldest = map.keys().next().value as number | undefined
|
||||||
if (oldest == null) break
|
if (oldest == null) break
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ export interface TaskProgressRequestCache<T> {
|
|||||||
|
|
||||||
export function createTaskProgressRequestCache<T>(options: TaskProgressRequestCacheOptions) {
|
export function createTaskProgressRequestCache<T>(options: TaskProgressRequestCacheOptions) {
|
||||||
const ttl = options.ttlMs
|
const ttl = options.ttlMs
|
||||||
const ttlValue = typeof ttl === 'number' ? ttl : 0
|
|
||||||
if (typeof ttl === 'number') {
|
if (typeof ttl === 'number') {
|
||||||
if (!(ttl > 0)) {
|
if (!(ttl > 0)) {
|
||||||
throw new Error('ttlMs 必须为正数: ' + ttl)
|
throw new Error('ttlMs 必须为正数: ' + ttl)
|
||||||
|
|||||||
Reference in New Issue
Block a user