提交更新
This commit is contained in:
@@ -24,6 +24,11 @@
|
||||
<div class="prompt-preview">{{ defaultAiPrompt }}</div>
|
||||
</div>
|
||||
|
||||
<div class="secret-card">
|
||||
<div class="section-title">密钥</div>
|
||||
<input v-model="cozeApiKey" class="secret-input" type="password" autocomplete="off" spellcheck="false" />
|
||||
</div>
|
||||
|
||||
<div class="run-row">
|
||||
<button type="button" class="btn-run" :disabled="parsing || !uploadedFiles.length" @click="parseFiles">
|
||||
{{ parsing ? '解析中...' : '解析并创建任务' }}
|
||||
@@ -34,9 +39,9 @@
|
||||
</div>
|
||||
<p class="loading-msg">Python 回传字段按 asin、国家、url、标题提交;后端接收分片后按 10 条一批调用 Coze。</p>
|
||||
|
||||
<div v-if="parseResult" class="parse-card">
|
||||
<div>任务 ID:{{ parseResult.taskId }}</div>
|
||||
<div>总行数:{{ parseResult.totalRows }},有效:{{ parseResult.acceptedRows }},分组:{{ parseResult.groupCount || 0 }},过滤:{{ parseResult.droppedRows }}</div>
|
||||
<div v-if="visibleTaskSummary" class="parse-card">
|
||||
<div>任务 ID:{{ visibleTaskSummary.taskId }}</div>
|
||||
<div>总行数:{{ visibleTaskSummary.totalRows }},有效:{{ visibleTaskSummary.acceptedRows }},分组:{{ visibleTaskSummary.groupCount || 0 }},过滤:{{ visibleTaskSummary.droppedRows }}</div>
|
||||
</div>
|
||||
<pre v-if="queuePayloadText" class="queue-payload">{{ queuePayloadText }}</pre>
|
||||
</aside>
|
||||
@@ -171,6 +176,8 @@ 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 = `请帮我排查以下亚马逊商品在英国及欧洲地区是否存在知识产权侵权风险。
|
||||
请直接给出明确结论(有侵权风险 或 未发现明显侵权风险),并严格按照以下三个维度提供精简的排查理由:
|
||||
外观维度: 评估产品外形、图案设计是否与欧洲/英国常见外观专利雷同。
|
||||
@@ -178,6 +185,7 @@ const defaultAiPrompt = `请帮我排查以下亚马逊商品在英国及欧洲
|
||||
标题维度: 排查标题中是否包含大牌商标、敏感词或版权保护词汇。
|
||||
结论:XX`
|
||||
const aiPrompt = ref('')
|
||||
const cozeApiKey = ref('')
|
||||
const parsing = ref(false)
|
||||
const pushing = ref(false)
|
||||
const queuePayloadText = ref('')
|
||||
@@ -203,6 +211,7 @@ 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 historyOnlyItems = computed(() =>
|
||||
historyItems.value.filter((i) => {
|
||||
@@ -215,6 +224,28 @@ function effectiveAiPrompt() {
|
||||
return aiPrompt.value.trim() || defaultAiPrompt
|
||||
}
|
||||
|
||||
function effectiveCozeApiKey() {
|
||||
return cozeApiKey.value.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 || '')),
|
||||
}
|
||||
: payload.data,
|
||||
}
|
||||
}
|
||||
|
||||
function uidForStorage() {
|
||||
return typeof window !== 'undefined' ? window.localStorage.getItem('uid') || '0' : '0'
|
||||
}
|
||||
@@ -223,6 +254,16 @@ function pollingKey() {
|
||||
return `appearance-patent:tasks:${uidForStorage()}`
|
||||
}
|
||||
|
||||
function toTaskSummary(result: AppearancePatentParseVo): TaskSummary {
|
||||
return {
|
||||
taskId: result.taskId,
|
||||
totalRows: result.totalRows,
|
||||
acceptedRows: result.acceptedRows,
|
||||
groupCount: result.groupCount,
|
||||
droppedRows: result.droppedRows,
|
||||
}
|
||||
}
|
||||
|
||||
function savePollingIds() {
|
||||
if (typeof window === 'undefined') return
|
||||
const ids = Array.from(new Set([...pollingTaskIds.value, ...pendingFileTaskIds.value]))
|
||||
@@ -274,6 +315,7 @@ async function selectFiles() {
|
||||
selectedFileNames.value = files.map((f) => f.relativePath || f.originalFilename || f.fileKey)
|
||||
parseResult.value = null
|
||||
parsedGroups.value = []
|
||||
queuedTaskSummary.value = null
|
||||
queuePayloadText.value = ''
|
||||
}
|
||||
|
||||
@@ -296,6 +338,7 @@ async function selectFolder() {
|
||||
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 文件`)
|
||||
} catch (error) {
|
||||
@@ -308,6 +351,10 @@ async function parseFiles() {
|
||||
ElMessage.warning('请先选择 Excel')
|
||||
return
|
||||
}
|
||||
if (!effectiveCozeApiKey()) {
|
||||
ElMessage.warning('请先填写密钥')
|
||||
return
|
||||
}
|
||||
parsing.value = true
|
||||
try {
|
||||
const files: UploadedFileRef[] = uploadedFiles.value.map((f) => ({
|
||||
@@ -315,8 +362,9 @@ async function parseFiles() {
|
||||
originalFilename: f.originalFilename,
|
||||
relativePath: f.relativePath,
|
||||
}))
|
||||
const res = await parseAppearancePatent(files, effectiveAiPrompt())
|
||||
const res = await parseAppearancePatent(files, effectiveAiPrompt(), effectiveCozeApiKey())
|
||||
parseResult.value = res
|
||||
queuedTaskSummary.value = null
|
||||
parsedGroups.value = res.groups?.length
|
||||
? res.groups
|
||||
: (res.items?.length
|
||||
@@ -341,7 +389,8 @@ async function parseFiles() {
|
||||
|
||||
async function pushToPythonQueue() {
|
||||
const api = getPywebviewApi()
|
||||
const taskId = parseResult.value?.taskId
|
||||
const currentParseResult = parseResult.value
|
||||
const taskId = currentParseResult?.taskId
|
||||
if (!taskId || !parsedRows.value.length) {
|
||||
ElMessage.warning('请先解析文件')
|
||||
return
|
||||
@@ -357,7 +406,8 @@ async function pushToPythonQueue() {
|
||||
ts: Date.now(),
|
||||
data: {
|
||||
taskId,
|
||||
prompt: parseResult.value?.aiPrompt || effectiveAiPrompt(),
|
||||
prompt: currentParseResult.aiPrompt || effectiveAiPrompt(),
|
||||
api_key: effectiveCozeApiKey(),
|
||||
groups: parsedGroups.value.map((group) => ({
|
||||
sourceFileKey: group.sourceFileKey || '',
|
||||
sourceFilename: group.sourceFilename || '',
|
||||
@@ -389,13 +439,14 @@ async function pushToPythonQueue() {
|
||||
})),
|
||||
},
|
||||
}
|
||||
queuePayloadText.value = JSON.stringify(payload, null, 2)
|
||||
queuePayloadText.value = JSON.stringify(payloadForDisplay(payload), null, 2)
|
||||
await activateAppearancePatentTask(taskId)
|
||||
const result = await api.enqueue_json(payload)
|
||||
if (!result?.success) {
|
||||
ElMessage.error(result?.error || '推送失败')
|
||||
return
|
||||
}
|
||||
queuedTaskSummary.value = toTaskSummary(currentParseResult)
|
||||
addPollingTask(taskId)
|
||||
clearParsedTask()
|
||||
await loadDashboard()
|
||||
@@ -721,9 +772,10 @@ onUnmounted(() => {
|
||||
.btn-run:disabled { opacity: .55; cursor: not-allowed; }
|
||||
.selected-files { margin-top: 14px; color: #999; font-size: 12px; word-break: break-all; }
|
||||
.selected-files span { display: block; margin: 4px 0; }
|
||||
.prompt-card { margin-bottom: 18px; }
|
||||
.prompt-card, .secret-card { margin-bottom: 18px; }
|
||||
.prompt-input { width: 100%; box-sizing: border-box; resize: vertical; min-height: 180px; padding: 10px 12px; border: 1px solid #333; border-radius: 8px; background: #202020; color: #d8d8d8; font-size: 12px; line-height: 1.6; outline: none; }
|
||||
.prompt-input:focus { border-color: #3498db; }
|
||||
.secret-input { width: 100%; box-sizing: border-box; height: 38px; padding: 0 12px; border: 1px solid #333; border-radius: 8px; background: #202020; color: #d8d8d8; font-size: 12px; outline: none; }
|
||||
.prompt-input:focus, .secret-input:focus { border-color: #3498db; }
|
||||
.prompt-default-label { margin-top: 10px; color: #8d8d8d; font-size: 12px; }
|
||||
.prompt-preview { margin-top: 10px; padding: 12px; border: 1px solid #2a2a2a; border-radius: 8px; background: #202020; color: #9ea7b3; font-size: 12px; line-height: 1.6; white-space: pre-wrap; }
|
||||
.parse-card, .queue-payload { margin-top: 14px; padding: 12px; border: 1px solid #2a2a2a; border-radius: 8px; background: #202020; color: #b8c1cc; font-size: 12px; }
|
||||
|
||||
Reference in New Issue
Block a user