提交打包

This commit is contained in:
super
2026-05-07 16:21:35 +08:00
parent a7d8f8be6c
commit e5d0b2d9ab
64 changed files with 1368 additions and 875 deletions

View File

@@ -28,11 +28,11 @@
<button type="button" class="btn-run" :disabled="parsing || !uploadedFiles.length" @click="parseFiles">
{{ parsing ? '解析中...' : '解析并创建任务' }}
</button>
<button type="button" class="btn-run btn-queue" :disabled="pushing || !parsedRows.length" @click="pushToPythonQueue">
<button type="button" class="btn-run btn-queue" :disabled="pushing || !parseResult?.taskId" @click="pushToPythonQueue">
{{ pushing ? '推送中...' : '推送到 Python 队列' }}
</button>
</div>
<p class="loading-msg">Python 回传字段按 asin国家url标题提交后端接收分片后按 10 条一批调用 Coze</p>
<p class="loading-msg">Python 回传字段按 asin国家url标题提交后端接收分片后按 10 条一批调用 Coze结果区展示真实 Coze 批次进度</p>
<div v-if="visibleTaskSummary" class="parse-card">
<div>任务 ID{{ visibleTaskSummary.taskId }}</div>
@@ -64,21 +64,6 @@
</div>
<div class="subsection-title">匹配任务</div>
<div class="result-list-wrap preview-wrap">
<div class="result-list-header">
<span>解析结果</span>
<span v-if="parsedRows.length" class="muted">显示首组 {{ previewRows.length }} / {{ parseResult?.groupCount || parsedGroups.length }} {{ parsedRows.length }} </span>
</div>
<div v-if="!parsedRows.length" class="empty-tasks">暂无解析结果</div>
<el-table v-else :data="previewRows" height="120" class="result-table">
<el-table-column prop="displayId" label="ID" width="90" />
<el-table-column prop="asin" label="ASIN" width="130" />
<el-table-column prop="country" label="国家" width="100" />
<el-table-column prop="title" label="标题" min-width="160" show-overflow-tooltip />
<el-table-column prop="url" label="URL" min-width="160" show-overflow-tooltip />
</el-table>
</div>
<div class="result-list-wrap">
<div class="result-list-header">
<span>当前任务</span>
@@ -151,13 +136,13 @@ import {
deleteAppearancePatentTask,
getAppearancePatentDashboard,
getAppearancePatentHistory,
getAppearancePatentQueuePayload,
getAppearancePatentResultDownloadUrl,
getAppearancePatentTaskProgressBatch,
parseAppearancePatent,
type AppearancePatentParsedGroup,
type AppearancePatentParsedPayloadDto,
type AppearancePatentDashboardVo,
type AppearancePatentHistoryItem,
type AppearancePatentParsedRow,
type AppearancePatentParseVo,
type UploadedFileRef,
type UploadFileVo,
@@ -171,7 +156,6 @@ import { createCategorizedTimers } from '@/shared/utils/categorized-timers'
const selectedFileNames = ref<string[]>([])
const uploadedFiles = ref<UploadFileVo[]>([])
const parseResult = ref<AppearancePatentParseVo | null>(null)
const parsedGroups = ref<AppearancePatentParsedGroup[]>([])
type TaskSummary = Pick<AppearancePatentParseVo, 'taskId' | 'totalRows' | 'acceptedRows' | 'groupCount' | 'droppedRows'>
const queuedTaskSummary = ref<TaskSummary | null>(null)
const defaultAiPrompt = `请帮我排查以下亚马逊商品在英国及欧洲地区是否存在知识产权侵权风险。
@@ -202,12 +186,24 @@ const dashboard = ref<AppearancePatentDashboardVo>({
})
const historyItems = ref<AppearancePatentHistoryItem[]>([])
const parsedRows = computed<AppearancePatentParsedRow[]>(() =>
parsedGroups.value.flatMap((group) => group.items || []),
)
const previewRows = computed(() => parsedGroups.value[0]?.items || [])
const visibleTaskSummary = computed(() => parseResult.value || queuedTaskSummary.value)
const currentItems = computed(() => historyItems.value.filter((i) => i.taskId != null && pollingTaskIds.value.includes(i.taskId)))
const pendingParseItem = computed<AppearancePatentHistoryItem | null>(() => {
const result = parseResult.value
if (!result?.taskId) return null
const exists = historyItems.value.some((item) => item.taskId === result.taskId)
if (exists) return null
return {
taskId: result.taskId,
sourceFilename: result.sourceFilename,
rowCount: result.acceptedRows,
taskStatus: 'PENDING',
success: false,
}
})
const currentItems = computed(() => {
const runningItems = historyItems.value.filter((i) => i.taskId != null && pollingTaskIds.value.includes(i.taskId))
return pendingParseItem.value ? [pendingParseItem.value, ...runningItems] : runningItems
})
const historyOnlyItems = computed(() =>
historyItems.value.filter((i) => {
const status = normalizeTaskStatus(i)
@@ -309,7 +305,6 @@ async function selectFiles() {
uploadedFiles.value = files
selectedFileNames.value = files.map((f) => f.relativePath || f.originalFilename || f.fileKey)
parseResult.value = null
parsedGroups.value = []
queuedTaskSummary.value = null
queuePayloadText.value = ''
}
@@ -332,7 +327,6 @@ async function selectFolder() {
uploadedFiles.value = files
selectedFileNames.value = result.items.map((item) => item.relativePath || item.absolutePath)
parseResult.value = null
parsedGroups.value = []
queuedTaskSummary.value = null
queuePayloadText.value = ''
ElMessage.success(`已选择文件夹内 ${result.items.length} 个 Excel 文件`)
@@ -360,19 +354,6 @@ async function parseFiles() {
const res = await parseAppearancePatent(files, effectiveAiPrompt(), effectiveCozeApiKey())
parseResult.value = res
queuedTaskSummary.value = null
parsedGroups.value = res.groups?.length
? res.groups
: (res.items?.length
? [{
sourceFileKey: res.items[0]?.sourceFileKey,
sourceFilename: res.items[0]?.sourceFilename,
groupKey: res.items[0]?.groupKey,
baseId: '',
displayId: res.items[0]?.displayId,
itemCount: res.items.length,
items: res.items,
}]
: [])
queuePayloadText.value = ''
ElMessage.success(`解析完成,共 ${res.groupCount || 0} 组 / ${res.acceptedRows}`)
} catch (e) {
@@ -386,7 +367,7 @@ async function pushToPythonQueue() {
const api = getPywebviewApi()
const currentParseResult = parseResult.value
const taskId = currentParseResult?.taskId
if (!taskId || !parsedRows.value.length) {
if (!taskId) {
ElMessage.warning('请先解析文件')
return
}
@@ -400,14 +381,20 @@ async function pushToPythonQueue() {
}
pushing.value = true
try {
const parsedPayload: AppearancePatentParsedPayloadDto = await getAppearancePatentQueuePayload(taskId)
const groups = parsedPayload.groups || []
const payload = {
type: 'appearance-patent-run',
ts: Date.now(),
data: {
taskId,
prompt: currentParseResult.aiPrompt || effectiveAiPrompt(),
prompt: parsedPayload.aiPrompt || currentParseResult.aiPrompt || effectiveAiPrompt(),
api_key: effectiveCozeApiKey(),
groups: parsedGroups.value.map((group) => ({
sourceFileCount: currentParseResult.sourceFileCount || 0,
totalRows: currentParseResult.totalRows || 0,
acceptedRows: currentParseResult.acceptedRows || 0,
groupCount: currentParseResult.groupCount || 0,
groups: groups.map((group) => ({
sourceFileKey: group.sourceFileKey || '',
sourceFilename: group.sourceFilename || '',
groupKey: group.groupKey || '',
@@ -425,20 +412,9 @@ async function pushToPythonQueue() {
title: row.title || '',
})),
})),
rows: parsedRows.value.map((row) => ({
sourceFileKey: row.sourceFileKey || '',
sourceFilename: row.sourceFilename || '',
rowToken: row.rowToken || '',
groupKey: row.groupKey || '',
id: row.displayId,
asin: row.asin,
country: row.country,
url: row.url || '',
title: row.title || '',
})),
},
}
queuePayloadText.value = JSON.stringify(payloadForDisplay(payload), null, 2)
queuePayloadText.value = `任务 ${taskId} 已准备推送,共 ${groups.length}`
await activateAppearancePatentTask(taskId)
const result = await api.enqueue_json(payload)
if (!result?.success) {
@@ -458,7 +434,6 @@ async function pushToPythonQueue() {
function clearParsedTask() {
parseResult.value = null
parsedGroups.value = []
queuePayloadText.value = ''
}
@@ -681,10 +656,10 @@ function pendingResultHint(item: AppearancePatentHistoryItem) {
if (!isResultPreparing(item)) return ''
const fileStatus = (item.fileStatus || '').toUpperCase()
if (fileStatus === 'RUNNING') {
return '任务已完成,正在请求 Coze 组装结果文件,下载按钮稍后出现'
return '任务已完成,正在等待 Coze 回流并组装结果文件,下载按钮稍后出现'
}
if (fileStatus === 'PENDING') {
return '任务已完成,结果文件已入队,正在等待后端生成'
return '任务已完成,结果文件已入队,正在等待后端开始处理'
}
return '任务已完成,正在生成结果文件,下载按钮稍后出现'
}

View File

@@ -52,7 +52,7 @@
{{ pushing ? '推送中...' : '推送到 Python 队列' }}
</button>
</div>
<p class="loading-msg">Python 回传字段按 idasin国家价格标题图片链接数组提交后端接收分片后按 10 条一批送检</p>
<p class="loading-msg">Python 回传字段按 idasin国家价格标题图片链接数组提交后端接收分片后按 10 条一批送检结果区展示真实 Coze 批次进度</p>
<div v-if="visibleTaskSummary" class="parse-card">
<div>任务 ID{{ visibleTaskSummary.taskId }}</div>
@@ -186,6 +186,7 @@ import {
type SimilarAsinParseVo,
type UploadedFileRef,
type UploadFileVo,
uploadTempFileToJava,
} from '@/shared/api/java-modules'
import { expandBrandFolderRecursive, type BrandExpandFolderItem } from '@/shared/api/brand'
import { getPywebviewApi } from '@/shared/bridges/pywebview'
@@ -326,7 +327,7 @@ async function uploadAppearancePathsToJava(paths: Array<string | BrandExpandFold
async function selectFiles() {
const api = getPywebviewApi()
if (!api?.select_brand_xlsx_files || !api.upload_file_to_java) {
ElMessage.warning('当前环境不支持文件选择或上传')
ElMessage.warning('当前桌面端未提供文件选择或上传能力')
return
}
const paths = await api.select_brand_xlsx_files()
@@ -342,8 +343,8 @@ async function selectFiles() {
async function selectFolder() {
const api = getPywebviewApi()
if (!api?.select_brand_folder) {
ElMessage.warning('当前环境不支持文件夹选择,请在本地客户端中打开')
if (!api?.select_brand_folder || !api.upload_file_to_java) {
ElMessage.warning('当前桌面端未提供文件夹选择或上传能力')
return
}
try {
@@ -721,10 +722,10 @@ function pendingResultHint(item: SimilarAsinHistoryItem) {
if (!isResultPreparing(item)) return ''
const fileStatus = (item.fileStatus || '').toUpperCase()
if (fileStatus === 'RUNNING') {
return '任务已完成,正在请求 Coze 组装结果文件,下载按钮稍后出现'
return '任务已完成,正在等待 Coze 回流并组装结果文件,下载按钮稍后出现'
}
if (fileStatus === 'PENDING') {
return '任务已完成,结果文件已入队,正在等待后端生成'
return '任务已完成,结果文件已入队,正在等待后端开始处理'
}
return '任务已完成,正在生成结果文件,下载按钮稍后出现'
}

View File

@@ -102,6 +102,25 @@ export interface UploadFileVo {
relativePath?: string;
}
export async function uploadTempFileToJava(file: File, relativePath?: string) {
const formData = new FormData()
formData.append('file', file)
if (relativePath) {
formData.append('relativePath', relativePath)
}
const response = await http.post<JavaApiResponse<UploadFileVo>>(
`${JAVA_API_PREFIX}/files/upload`,
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
timeout: 120000,
},
)
return response.data
}
export interface DedupeResultItem {
resultId?: number;
sourceFilename: string;
@@ -1452,6 +1471,7 @@ export interface AppearancePatentParsedRow {
groupKey?: string;
asin: string;
country: string;
price?: string;
url?: string;
title?: string;
}
@@ -1479,6 +1499,16 @@ export interface AppearancePatentParseVo {
groups?: AppearancePatentParsedGroup[];
}
export interface AppearancePatentParsedPayloadDto {
aiPrompt?: string;
apiKey?: string;
sourceFiles?: UploadedFileRef[];
headers?: string[];
items?: AppearancePatentParsedRow[];
groups?: AppearancePatentParsedGroup[];
allItems?: AppearancePatentParsedRow[];
}
export interface AppearancePatentDashboardVo {
pendingTaskCount: number;
processedTaskCount: number;
@@ -1545,6 +1575,24 @@ export function parseAppearancePatent(files: UploadedFileRef[], aiPrompt: string
);
}
export function getAppearancePatentParsedPayload(taskId: number) {
return unwrapJavaResponse(
get<JavaApiResponse<AppearancePatentParsedPayloadDto>>(
`${JAVA_API_PREFIX}/appearance-patent/tasks/${taskId}/parsed-payload`,
{ params: { user_id: getCurrentUserId() } },
),
);
}
export function getAppearancePatentQueuePayload(taskId: number) {
return unwrapJavaResponse(
get<JavaApiResponse<AppearancePatentParsedPayloadDto>>(
`${JAVA_API_PREFIX}/appearance-patent/tasks/${taskId}/queue-payload`,
{ params: { user_id: getCurrentUserId() } },
),
);
}
export function getAppearancePatentDashboard() {
return unwrapJavaResponse(
get<JavaApiResponse<AppearancePatentDashboardVo>>(