修改多文件

This commit is contained in:
super
2026-04-02 20:37:35 +08:00
parent 99e94a5e57
commit 4b50542779

View File

@@ -224,9 +224,14 @@ import {
} from '@/shared/api/java-modules' } from '@/shared/api/java-modules'
import { getPywebviewApi, type UploadedJavaFile } from '@/shared/bridges/pywebview' import { getPywebviewApi, type UploadedJavaFile } from '@/shared/bridges/pywebview'
interface SessionDeleteBrandItem extends DeleteBrandResultItem {
_pushed?: boolean
_completed?: boolean
}
interface StoredCurrentTask { interface StoredCurrentTask {
taskId: number taskId: number
items: DeleteBrandResultItem[] items: SessionDeleteBrandItem[]
createdAt: number createdAt: number
queuePushResult?: string queuePushResult?: string
queuePayloadText?: string queuePayloadText?: string
@@ -318,6 +323,84 @@ const historySectionItems = computed(() =>
); );
const hasVisibleItems = computed(() => currentSectionItems.value.length > 0 || historySectionItems.value.length > 0) const hasVisibleItems = computed(() => currentSectionItems.value.length > 0 || historySectionItems.value.length > 0)
function persistSessionTasks() {
if (typeof window !== 'undefined') {
window.localStorage.setItem(getStorageKey(), JSON.stringify(sessionTasks.value))
}
}
function isMultiFileTask(taskId?: number) {
if (!taskId) return false
const sessionTask = sessionTasks.value.find(t => t.taskId === taskId)
return (sessionTask?.items.length || 0) > 1
}
function findSessionTask(taskId?: number) {
if (!taskId) return null
return sessionTasks.value.find(t => t.taskId === taskId) || null
}
function isSameDeleteBrandItem(left: Pick<DeleteBrandResultItem, 'resultId' | 'fileKey' | 'sourceFilename'> | null | undefined,
right: Pick<DeleteBrandResultItem, 'resultId' | 'fileKey' | 'sourceFilename'> | null | undefined) {
if (!left || !right) return false
if (left.resultId != null && right.resultId != null) {
return left.resultId === right.resultId
}
if (left.fileKey && right.fileKey) {
return left.fileKey === right.fileKey
}
return left.sourceFilename === right.sourceFilename
}
function findSessionItem(taskId: number | undefined, item: DeleteBrandResultItem) {
const sessionTask = findSessionTask(taskId)
if (!sessionTask) return null
return sessionTask.items.find(i => isSameDeleteBrandItem(i, item)) || null
}
function updateCompletedItemsFromProgress(taskId: number | undefined) {
if (!taskId) return false
const sessionTask = findSessionTask(taskId)
if (!sessionTask) return false
let changed = false
const info = taskDetails.value[taskId]?.line_progress?.info
// 多文件任务优先依据后端 finished_files 同步已完成文件数量。
// 规则:按 sessionTask.items 的顺序,标记「已推送」中的前 N 个为 completed。
if (isMultiFileTask(taskId) && info?.finished_files != null && info.finished_files >= 0) {
const pushedItems = sessionTask.items.filter(i => i._pushed)
const shouldCompleted = Math.max(0, Math.min(info.finished_files, pushedItems.length))
for (let i = 0; i < shouldCompleted; i += 1) {
if (!pushedItems[i]._completed) {
pushedItems[i]._completed = true
changed = true
}
}
}
// 兼容单文件/兜底:当当前文件行进度到达末行时,标记活动文件完成。
if (info?.file_name && info.current_line != null && info.total_lines != null && info.total_lines > 0) {
if (info.current_line >= info.total_lines) {
const activeItem = currentSectionItems.value.find(item => getItemKey(item) === activeItemKey.value)
const sessionItem = activeItem && activeItem.taskId === taskId
? findSessionItem(taskId, activeItem)
: sessionTask.items.find(i => i.sourceFilename === info.file_name)
if (sessionItem && !sessionItem._completed) {
sessionItem._completed = true
changed = true
}
}
}
if (changed) {
persistSessionTasks()
}
return changed
}
function getTaskStatus(taskId?: number) { function getTaskStatus(taskId?: number) {
if (!taskId) return '' if (!taskId) return ''
return taskDetails.value[taskId]?.task?.status || '' return taskDetails.value[taskId]?.task?.status || ''
@@ -342,14 +425,20 @@ function shouldShowProgress(item: DeleteBrandResultItem) {
function normalizeDeleteBrandItems(items: DeleteBrandResultItem[]) { function normalizeDeleteBrandItems(items: DeleteBrandResultItem[]) {
return items.map((item) => { return items.map((item) => {
if (item.matchStatus === 'MATCHED') { if (item.matchStatus === 'MATCHED') {
return item return {
...item,
_pushed: false,
_completed: false,
} as SessionDeleteBrandItem
} }
return { return {
...item, ...item,
matched: false, matched: false,
openStoreUrl: undefined, openStoreUrl: undefined,
error: item.error || undefined, error: item.error || undefined,
} _pushed: false,
_completed: false,
} as SessionDeleteBrandItem
}) })
} }
@@ -404,11 +493,14 @@ function formatProgress(taskId: number) {
if (info.file_index && info.file_total) parts.push(`文件:${info.file_index}/${info.file_total}`) if (info.file_index && info.file_total) parts.push(`文件:${info.file_index}/${info.file_total}`)
if (info.file_name) parts.push(`当前文件:${info.file_name}`) if (info.file_name) parts.push(`当前文件:${info.file_name}`)
if (info.current_line != null && info.total_lines != null) { if (info.current_line != null && info.total_lines != null) {
parts.push(`进度${info.current_line}/${info.total_lines}`) parts.push(`${isMultiFileTask(taskId) ? '当前文件进度' : '进度'}${info.current_line}/${info.total_lines}`)
} }
if (info.current_country) parts.push(`国家:${info.current_country}`) if (info.current_country) parts.push(`国家:${info.current_country}`)
if (info.current_asin) parts.push(`ASIN${info.current_asin}`) if (info.current_asin) parts.push(`ASIN${info.current_asin}`)
if (info.finished_files != null) parts.push(`已完成文件:${info.finished_files}`) if (info.finished_files != null) {
const total = info.file_total && info.file_total > 0 ? `/${info.file_total}` : ''
parts.push(`已完成文件:${info.finished_files}${total}`)
}
return parts.join('') return parts.join('')
} }
@@ -446,34 +538,41 @@ function getPollingTaskIds() {
function getQueueStatus(item: DeleteBrandResultItem) { function getQueueStatus(item: DeleteBrandResultItem) {
const taskId = item.taskId const taskId = item.taskId
if (!taskId) return '' if (!taskId) return ''
const sessionTask = sessionTasks.value.find(t => t.taskId === taskId) const sessionTask = findSessionTask(taskId)
if (!sessionTask) return '' if (!sessionTask) return ''
const sessionItem = findSessionItem(taskId, item)
const status = getTaskStatus(taskId) const status = getTaskStatus(taskId)
if (status === 'SUCCESS' || status === 'FAILED' || item.taskStatus === 'SUCCESS' || item.taskStatus === 'FAILED') { const info = taskDetails.value[taskId]?.line_progress
const multiFileTask = isMultiFileTask(taskId)
if (!multiFileTask && (status === 'SUCCESS' || status === 'FAILED' || item.taskStatus === 'SUCCESS' || item.taskStatus === 'FAILED')) {
return '已被全局判定为终态' return '已被全局判定为终态'
} }
const sessionItem = sessionTask.items.find(i => i.resultId === item.resultId || i.sourceFilename === item.sourceFilename)
const info = taskDetails.value[taskId]?.line_progress
// 此时这个特定文件是否正好被后端报了进度名
if (status === 'RUNNING' && info?.has_progress && info?.info?.file_name === item.sourceFilename) { if (status === 'RUNNING' && info?.has_progress && info?.info?.file_name === item.sourceFilename) {
return '处理中' return '处理中'
} }
// 查查是否已经完结了这个特定文件 if (sessionItem?._completed) {
const detail = taskDetails.value[taskId] return '本文件解析完毕'
if (detail?.items) { }
// 后端返回的 items 是 `resultJson` 解析来的,里面只含有已经做完的!
const finished = detail.items.find((i: DeleteBrandResultItem) => i.sourceFilename === item.sourceFilename) if (multiFileTask && status === 'SUCCESS') {
if (finished) { return '本文件解析完毕'
return '本文件解析完毕' }
if (!multiFileTask) {
const detail = taskDetails.value[taskId]
if (detail?.items) {
const finished = detail.items.find((i: DeleteBrandResultItem) => isSameDeleteBrandItem(i, item))
if (finished && status === 'SUCCESS') {
return '本文件解析完毕'
}
} }
} }
if (sessionItem && (sessionItem as any)._pushed) { if (sessionItem?._pushed) {
return '已入队' return '已入队'
} }
@@ -497,12 +596,14 @@ function mergeTaskDetailItemsIntoSession(detail: DeleteBrandTaskDetailVo) {
let changed = false let changed = false
const mergedItems = sessionTask.items.map((item) => { const mergedItems = sessionTask.items.map((item) => {
const latest = detail.items?.find((candidate) => candidate.resultId === item.resultId || candidate.sourceFilename === item.sourceFilename) const latest = detail.items?.find((candidate) => isSameDeleteBrandItem(candidate, item))
if (!latest) return item if (!latest) return item
const merged = { const merged = {
...item, ...item,
...latest, ...latest,
success: item.success ?? latest.success, success: item.success ?? latest.success,
_pushed: item._pushed,
_completed: item._completed,
} }
if (JSON.stringify(merged) !== JSON.stringify(item)) { if (JSON.stringify(merged) !== JSON.stringify(item)) {
changed = true changed = true
@@ -516,8 +617,8 @@ function mergeTaskDetailItemsIntoSession(detail: DeleteBrandTaskDetailVo) {
changed = true changed = true
} }
if (changed && typeof window !== 'undefined') { if (changed) {
window.localStorage.setItem(getStorageKey(), JSON.stringify(sessionTasks.value)) persistSessionTasks()
} }
return changed return changed
} }
@@ -536,6 +637,9 @@ async function refreshTaskDetails(taskIds?: number[]) {
if (mergeTaskDetailItemsIntoSession(detail)) { if (mergeTaskDetailItemsIntoSession(detail)) {
changed = true changed = true
} }
if (updateCompletedItemsFromProgress(id)) {
changed = true
}
} }
} }
if (changed) { if (changed) {
@@ -833,6 +937,8 @@ function findNextAutoRunnableItem() {
return currentSectionItems.value.find((item) => { return currentSectionItems.value.find((item) => {
if (!item.openStoreUrl) return false if (!item.openStoreUrl) return false
if (getItemKey(item) === activeItemKey.value) return false if (getItemKey(item) === activeItemKey.value) return false
const sessionItem = findSessionItem(item.taskId, item)
if (sessionItem?._completed) return false
return getQueueStatus(item) === '未入队' return getQueueStatus(item) === '未入队'
}) })
} }
@@ -870,9 +976,10 @@ async function runItem(item: DeleteBrandResultItem, options?: { auto?: boolean }
if (pushResult?.success) { if (pushResult?.success) {
qpr = `已推送文件 ${item.sourceFilename},当前队列长度:${pushResult.queue_size ?? '-'}` qpr = `已推送文件 ${item.sourceFilename},当前队列长度:${pushResult.queue_size ?? '-'}`
const sessionItem = sessionTask.items.find(i => i.resultId === item.resultId || i.sourceFilename === item.sourceFilename) const sessionItem = findSessionItem(taskId, item)
if (sessionItem) { if (sessionItem) {
(sessionItem as any)._pushed = true sessionItem._pushed = true
sessionItem._completed = false
} }
activeItemKey.value = getItemKey(item) activeItemKey.value = getItemKey(item)
saveSessionTask(taskId, sessionTask.items, qpr, queuePayloadText.value) saveSessionTask(taskId, sessionTask.items, qpr, queuePayloadText.value)
@@ -892,10 +999,21 @@ async function maybeAutoAdvance() {
if (currentKey) { if (currentKey) {
const currentItem = currentSectionItems.value.find(item => getItemKey(item) === currentKey) const currentItem = currentSectionItems.value.find(item => getItemKey(item) === currentKey)
if (currentItem) { if (currentItem) {
const taskId = currentItem.taskId
const multiFileTask = isMultiFileTask(taskId)
if (multiFileTask) {
updateCompletedItemsFromProgress(taskId)
}
const status = getQueueStatus(currentItem) const status = getQueueStatus(currentItem)
if (status === '已入队' || status === '处理中') { if (status === '已入队' || status === '处理中') {
return return
} }
if (multiFileTask) {
const sessionItem = findSessionItem(taskId, currentItem)
if (sessionItem && !sessionItem._completed) {
return
}
}
} }
} }