From fba85ca365b375a25c475a1f0daad359b8fa26a1 Mon Sep 17 00:00:00 2001 From: super <2903208875@qq.com> Date: Fri, 3 Apr 2026 00:53:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=8E=A5=E5=8F=A3=E8=BF=9B?= =?UTF-8?q?=E5=BA=A6=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/.env | 3 +- app/amazon/__pycache__/main.cpython-312.pyc | Bin 25649 -> 26386 bytes .../model/vo/DeleteBrandTaskDetailVo.java | 3 + .../vo/DeleteBrandTaskFileProgressVo.java | 27 +++++ .../service/DeleteBrandRunService.java | 72 ++++++++++++- .../brand/components/BrandDeleteBrandTab.vue | 95 +++++++++++++----- frontend-vue/src/shared/api/java-modules.ts | 10 ++ 7 files changed, 182 insertions(+), 28 deletions(-) create mode 100644 backend-java/src/main/java/com/nanri/aiimage/modules/deletebrand/model/vo/DeleteBrandTaskFileProgressVo.java diff --git a/app/.env b/app/.env index e40b987..856e41a 100644 --- a/app/.env +++ b/app/.env @@ -12,6 +12,7 @@ zn_username=%E8%87%AA%E5%8A%A8%E5%8C%96_Robot client_name=ShuFuAI -java_api_base=http://8.136.19.173:18080 +java_api_base=http://127.0.0.1:18080 +# java_api_base=http://8.136.19.173:18080 diff --git a/app/amazon/__pycache__/main.cpython-312.pyc b/app/amazon/__pycache__/main.cpython-312.pyc index 702fd9b5266223f58b6fb523a824642bf08bd99a..e5f9bdadb57b1b737022f09e0e8975f52047f90f 100644 GIT binary patch delta 4782 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 delta 4241 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 diff --git a/backend-java/src/main/java/com/nanri/aiimage/modules/deletebrand/model/vo/DeleteBrandTaskDetailVo.java b/backend-java/src/main/java/com/nanri/aiimage/modules/deletebrand/model/vo/DeleteBrandTaskDetailVo.java index 9bf9829..b60ca27 100644 --- a/backend-java/src/main/java/com/nanri/aiimage/modules/deletebrand/model/vo/DeleteBrandTaskDetailVo.java +++ b/backend-java/src/main/java/com/nanri/aiimage/modules/deletebrand/model/vo/DeleteBrandTaskDetailVo.java @@ -17,4 +17,7 @@ public class DeleteBrandTaskDetailVo { @Schema(description = "任务结果项快照") private List items = new ArrayList<>(); + + @Schema(description = "文件级进度快照") + private List fileProgress = new ArrayList<>(); } diff --git a/backend-java/src/main/java/com/nanri/aiimage/modules/deletebrand/model/vo/DeleteBrandTaskFileProgressVo.java b/backend-java/src/main/java/com/nanri/aiimage/modules/deletebrand/model/vo/DeleteBrandTaskFileProgressVo.java new file mode 100644 index 0000000..0c0a024 --- /dev/null +++ b/backend-java/src/main/java/com/nanri/aiimage/modules/deletebrand/model/vo/DeleteBrandTaskFileProgressVo.java @@ -0,0 +1,27 @@ +package com.nanri.aiimage.modules.deletebrand.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "删除品牌任务中的文件级进度") +public class DeleteBrandTaskFileProgressVo { + + @Schema(description = "文件标识(优先 fileKey)") + private String fileKey; + + @Schema(description = "源文件名") + private String sourceFilename; + + @Schema(description = "已处理行数") + private Integer processedRows; + + @Schema(description = "总行数") + private Integer totalRows; + + @Schema(description = "百分比(0-100)") + private Integer percent; + + @Schema(description = "文件状态:PENDING/RUNNING/COMPLETED/FAILED") + private String status; +} diff --git a/backend-java/src/main/java/com/nanri/aiimage/modules/deletebrand/service/DeleteBrandRunService.java b/backend-java/src/main/java/com/nanri/aiimage/modules/deletebrand/service/DeleteBrandRunService.java index 75fee5d..9152476 100644 --- a/backend-java/src/main/java/com/nanri/aiimage/modules/deletebrand/service/DeleteBrandRunService.java +++ b/backend-java/src/main/java/com/nanri/aiimage/modules/deletebrand/service/DeleteBrandRunService.java @@ -25,6 +25,7 @@ import com.nanri.aiimage.modules.deletebrand.model.vo.DeleteBrandResultItemVo; import com.nanri.aiimage.modules.deletebrand.model.vo.DeleteBrandRunVo; import com.nanri.aiimage.modules.deletebrand.model.vo.DeleteBrandTaskDeletionStatusVo; import com.nanri.aiimage.modules.deletebrand.model.vo.DeleteBrandTaskDetailVo; +import com.nanri.aiimage.modules.deletebrand.model.vo.DeleteBrandTaskFileProgressVo; import com.nanri.aiimage.modules.deletebrand.model.vo.DeleteBrandTaskItemVo; import com.nanri.aiimage.modules.file.service.LocalFileStorageService; import com.nanri.aiimage.modules.file.service.oss.OssStorageService; @@ -569,9 +570,11 @@ public class DeleteBrandRunService { DeleteBrandLineProgressVo progressVo = buildLineProgress(task.getId(), progress); DeleteBrandTaskDetailVo detail = new DeleteBrandTaskDetailVo(); + List taskItems = resolveTaskResultItems(task); detail.setTask(taskVo); detail.setLine_progress(progressVo); - detail.setItems(resolveTaskResultItems(task)); + detail.setItems(taskItems); + detail.setFileProgress(buildFileProgress(task, taskItems, progressVo)); return detail; } @@ -602,6 +605,73 @@ public class DeleteBrandRunService { } } + private List buildFileProgress(FileTaskEntity task, + List taskItems, + DeleteBrandLineProgressVo progressVo) { + if (taskItems == null || taskItems.isEmpty()) { + return List.of(); + } + + String taskStatus = task == null ? null : task.getStatus(); + DeleteBrandLineProgressInfoVo info = progressVo == null ? null : progressVo.getInfo(); + Integer finishedFiles = info == null ? null : info.getFinished_files(); + String runningFileName = info == null ? null : info.getFile_name(); + Integer currentLine = info == null ? null : info.getCurrent_line(); + Integer totalLines = info == null ? null : info.getTotal_lines(); + + List fileProgress = new ArrayList<>(); + int completedAssigned = 0; + int normalizedFinished = finishedFiles == null ? 0 : Math.max(0, finishedFiles); + + for (DeleteBrandResultItemVo item : taskItems) { + if (item == null) { + continue; + } + + DeleteBrandTaskFileProgressVo fp = new DeleteBrandTaskFileProgressVo(); + fp.setFileKey(item.getFileKey()); + fp.setSourceFilename(item.getSourceFilename()); + + Integer itemTotalRows = item.getTotalRows() == null ? 0 : Math.max(item.getTotalRows(), 0); + fp.setTotalRows(itemTotalRows); + + String status = "PENDING"; + int processedRows = 0; + int percent = 0; + + if ("SUCCESS".equals(taskStatus)) { + status = "COMPLETED"; + processedRows = itemTotalRows; + percent = 100; + } else if ("FAILED".equals(taskStatus)) { + status = "FAILED"; + processedRows = Math.min(itemTotalRows, Math.max(0, currentLine == null ? 0 : currentLine)); + percent = itemTotalRows > 0 ? Math.min(100, (int) Math.round(processedRows * 100.0 / itemTotalRows)) : 0; + } else { + if (completedAssigned < normalizedFinished) { + status = "COMPLETED"; + processedRows = itemTotalRows; + percent = 100; + completedAssigned++; + } else if (runningFileName != null && runningFileName.equals(item.getSourceFilename())) { + status = "RUNNING"; + processedRows = Math.min(itemTotalRows, Math.max(0, currentLine == null ? 0 : currentLine)); + if (totalLines != null && totalLines > 0) { + percent = Math.min(100, Math.max(0, (int) Math.round(processedRows * 100.0 / totalLines))); + } else if (itemTotalRows > 0) { + percent = Math.min(100, Math.max(0, (int) Math.round(processedRows * 100.0 / itemTotalRows))); + } + } + } + + fp.setProcessedRows(processedRows); + fp.setPercent(percent); + fp.setStatus(status); + fileProgress.add(fp); + } + return fileProgress; + } + private FileTaskEntity refreshIndexedMatchesIfNeeded(FileTaskEntity task) { if (task == null || task.getResultJson() == null || task.getResultJson().isBlank()) { return task; diff --git a/frontend-vue/src/pages/brand/components/BrandDeleteBrandTab.vue b/frontend-vue/src/pages/brand/components/BrandDeleteBrandTab.vue index 631f37a..07f3cb5 100644 --- a/frontend-vue/src/pages/brand/components/BrandDeleteBrandTab.vue +++ b/frontend-vue/src/pages/brand/components/BrandDeleteBrandTab.vue @@ -115,13 +115,13 @@
任务进度 - {{ formatProgressPercent(item.taskId!) }}% + {{ formatProgressPercent(item) }}%
+ :style="{ width: `${formatProgressPercent(item)}%` }">
-
{{ formatProgress(item.taskId!) }}
+
{{ formatProgress(item) }}
{{ formatPreview(item.previewRows) }} @@ -167,13 +167,13 @@
任务进度 - {{ formatProgressPercent(item.taskId!) }}% + {{ formatProgressPercent(item) }}%
+ :style="{ width: `${formatProgressPercent(item)}%` }">
-
{{ formatProgress(item.taskId!) }}
+
{{ formatProgress(item) }}
{{ formatPreview(item.previewRows) }} @@ -421,25 +421,30 @@ function shouldShowProgress(item: DeleteBrandResultItem) { if (!taskId) return false const progress = taskDetails.value[taskId]?.line_progress + const status = getTaskStatus(taskId) const multiFileTask = isMultiFileTask(taskId) const qs = getQueueStatus(item) - // 已完成/终态后隐藏进度条。 - if (qs === '本文件解析完毕' || qs === '已被全局判定为终态') { + if (multiFileTask) { + const sessionItem = findSessionItem(taskId, item) + const isActiveItem = getItemKey(item) === activeItemKey.value + const isProgressTarget = Boolean(progress?.has_progress && progress?.info?.file_name === item.sourceFilename) + + // 多文件任务下,展示规则更宽松: + // 1) 当前活跃文件;2) 后端进度指向的文件;3) 已推送文件;4) 已完成文件(任务未终态时保留)。 + if (isActiveItem || isProgressTarget || sessionItem?._pushed) { + return true + } + if ((status === 'RUNNING' || status === 'PENDING' || !status) && sessionItem?._completed) { + return true + } + return false } - if (multiFileTask) { - const sessionItem = findSessionItem(taskId, item) - // 多文件任务:未入队的文件不展示同一个 task 的公共进度,避免“两个文件同时在跑”的错觉。 - if (!sessionItem?._pushed) { - return false - } - - if (progress?.has_progress && progress?.info?.file_name) { - return progress.info.file_name === item.sourceFilename - } - return true + // 单文件任务:完成/终态后隐藏。 + if (qs === '本文件解析完毕' || qs === '已被全局判定为终态') { + return false } if (progress?.has_progress || progress?.info) { @@ -507,10 +512,40 @@ function updateSummary(items: DeleteBrandResultItem[]) { } } -function formatProgress(taskId: number) { +function getFileProgress(item: DeleteBrandResultItem) { + const taskId = item.taskId + if (!taskId) return null + const detail = taskDetails.value[taskId] + const fileProgress = detail?.fileProgress || [] + return fileProgress.find((fp) => { + if (fp.fileKey && item.fileKey) return fp.fileKey === item.fileKey + if (fp.sourceFilename && item.sourceFilename) return fp.sourceFilename === item.sourceFilename + return false + }) || null +} + +function formatProgress(item: DeleteBrandResultItem) { + const taskId = item.taskId if (!taskId) return '' + const detail = taskDetails.value[taskId] const info = detail?.line_progress?.info + const fp = getFileProgress(item) + + if (fp) { + const parts: string[] = [] + const processedRows = fp.processedRows ?? 0 + const totalRows = fp.totalRows ?? 0 + if (fp.status) parts.push(`文件状态:${fp.status}`) + parts.push(`文件进度:${processedRows}/${totalRows}`) + if (info?.finished_files != null) { + const total = info.file_total && info.file_total > 0 ? `/${info.file_total}` : '' + parts.push(`已完成文件:${info.finished_files}${total}`) + } + if (info?.phase) parts.push(`阶段:${info.phase}`) + return parts.join('|') + } + if (!detail?.line_progress?.has_progress || !info) { const status = detail?.task?.status return status ? `任务状态:${status}` : '' @@ -532,8 +567,15 @@ function formatProgress(taskId: number) { return parts.join('|') } -function formatProgressPercent(taskId: number) { +function formatProgressPercent(item: DeleteBrandResultItem) { + const taskId = item.taskId if (!taskId) return 0 + + const fp = getFileProgress(item) + if (fp) { + return Math.max(0, Math.min(100, fp.percent ?? 0)) + } + const info = taskDetails.value[taskId]?.line_progress?.info if (!info) return 0 @@ -578,20 +620,21 @@ function getQueueStatus(item: DeleteBrandResultItem) { return '已被全局判定为终态' } - // 多文件:未推送的文件必须保持“未入队”,避免被同 task 的公共 RUNNING 状态误判成“处理中”。 - if (multiFileTask && !sessionItem?._pushed && !sessionItem?._completed) { - return '未入队' - } - // 先看前端会话态:一旦该文件已判定完成,优先展示完成,避免被 RUNNING 覆盖导致链式推进卡住。 if (sessionItem?._completed) { return '本文件解析完毕' } + // 多文件场景下,如果后端进度明确指向当前文件,即使本地 _pushed 丢失也应判定为处理中(例如刷新页面后恢复场景)。 if (status === 'RUNNING' && info?.has_progress && info?.info?.file_name === item.sourceFilename) { return '处理中' } + // 多文件:未推送且未完成,才视为未入队。 + if (multiFileTask && !sessionItem?._pushed && !sessionItem?._completed) { + return '未入队' + } + if (multiFileTask && status === 'SUCCESS') { return '本文件解析完毕' } diff --git a/frontend-vue/src/shared/api/java-modules.ts b/frontend-vue/src/shared/api/java-modules.ts index 3f93ae2..73124d4 100644 --- a/frontend-vue/src/shared/api/java-modules.ts +++ b/frontend-vue/src/shared/api/java-modules.ts @@ -200,10 +200,20 @@ export interface DeleteBrandTaskItem { downloadFilename?: string } +export interface DeleteBrandTaskFileProgress { + fileKey?: string + sourceFilename?: string + processedRows?: number + totalRows?: number + percent?: number + status?: 'PENDING' | 'RUNNING' | 'COMPLETED' | 'FAILED' +} + export interface DeleteBrandTaskDetailVo { task: DeleteBrandTaskItem line_progress: DeleteBrandLineProgress items?: DeleteBrandResultItem[] + fileProgress?: DeleteBrandTaskFileProgress[] } export interface DeleteBrandTaskBatchVo {