From 225d13fb6e29b8b20bef85cdc09769d08c0a5bfe Mon Sep 17 00:00:00 2001 From: super <2903208875@qq.com> Date: Fri, 29 May 2026 16:49:18 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BC=98=E5=8C=96=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/appearance-patent-BoTBnU7J.css | 1 + app/assets/appearance-patent-efxpNAXi.css | 1 - app/assets/appearance-patent.js | 2 +- .../{brand-jr47vQUd.js => brand-COze15GJ.js} | 2 +- app/assets/collect-data-6h7Mh27f.css | 1 - app/assets/collect-data-DPGAQszU.css | 1 + app/assets/collect-data.js | 2 +- app/assets/convert.js | 2 +- app/assets/dedupe.js | 2 +- app/assets/delete-brand.js | 2 +- ...s-DzYrjxib.js => java-modules-B8c-YG5x.js} | 2 +- app/assets/patrol-delete.js | 2 +- app/assets/price-track.js | 2 +- app/assets/product-risk.js | 2 +- app/assets/query-asin.js | 2 +- app/assets/shop-match.js | 2 +- app/assets/similar-asin-Bl4LsbT8.css | 1 + app/assets/similar-asin-CVYG_iIM.css | 1 - app/assets/similar-asin.js | 2 +- app/assets/split.js | 2 +- .../{zh-cn-z8KAT-CE.js => zh-cn-CscLo6na.js} | 2 +- app/new_web_source/convert.html | 4 +- app/new_web_source/dedupe.html | 4 +- app/new_web_source/delete-brand.html | 4 +- app/new_web_source/split.html | 4 +- .../model/dto/CollectDataFiltersDto.java | 17 +- .../client/SimilarAsinCozeClient.java | 47 ++-- .../model/dto/SimilarAsinParseRequest.java | 5 + .../dto/SimilarAsinParsedPayloadDto.java | 3 + .../model/vo/SimilarAsinParseVo.java | 3 + .../service/SimilarAsinTaskService.java | 211 +++++++++++++++--- .../db/V51__coze_credential_pool.sql | 2 +- ...V57__update_appearance_patent_workflow.sql | 4 + .../brand/components/BrandCollectDataTab.vue | 207 +++++++---------- .../brand/components/BrandSimilarAsinTab.vue | 25 ++- frontend-vue/src/shared/api/java-modules.ts | 14 +- 36 files changed, 370 insertions(+), 220 deletions(-) create mode 100644 app/assets/appearance-patent-BoTBnU7J.css delete mode 100644 app/assets/appearance-patent-efxpNAXi.css rename app/assets/{brand-jr47vQUd.js => brand-COze15GJ.js} (57%) delete mode 100644 app/assets/collect-data-6h7Mh27f.css create mode 100644 app/assets/collect-data-DPGAQszU.css rename app/assets/{java-modules-DzYrjxib.js => java-modules-B8c-YG5x.js} (99%) create mode 100644 app/assets/similar-asin-Bl4LsbT8.css delete mode 100644 app/assets/similar-asin-CVYG_iIM.css rename app/assets/{zh-cn-z8KAT-CE.js => zh-cn-CscLo6na.js} (98%) create mode 100644 backend-java/src/main/resources/db/V57__update_appearance_patent_workflow.sql diff --git a/app/assets/appearance-patent-BoTBnU7J.css b/app/assets/appearance-patent-BoTBnU7J.css new file mode 100644 index 0000000..96fac61 --- /dev/null +++ b/app/assets/appearance-patent-BoTBnU7J.css @@ -0,0 +1 @@ +.module-page[data-v-7a18cb78]{min-height:100vh;background:#1a1a1a}.main-content[data-v-7a18cb78]{display:flex;height:calc(100vh - 56px);min-height:calc(100vh - 56px)}.left-panel[data-v-7a18cb78]{width:400px;background:#1e1e1e;padding:20px;overflow-y:auto;border-right:1px solid #2a2a2a}.right-panel[data-v-7a18cb78]{flex:1;min-width:0;background:#1a1a1a;display:flex;flex-direction:column}.section-title[data-v-7a18cb78],.subsection-title[data-v-7a18cb78]{font-size:13px;color:#bbb;margin-bottom:10px}.upload-zone[data-v-7a18cb78]{border:1px dashed #3a3a3a;border-radius:10px;padding:18px;background:#252525;margin-bottom:18px}.hint[data-v-7a18cb78],.loading-msg[data-v-7a18cb78],.files[data-v-7a18cb78],.muted[data-v-7a18cb78]{color:#888;font-size:12px;line-height:1.5}.link[data-v-7a18cb78]{color:#6ea8fe;text-decoration:none}.link[data-v-7a18cb78]:hover{color:#9fc5ff}.btns[data-v-7a18cb78],.run-row[data-v-7a18cb78]{display:flex;gap:10px;flex-wrap:wrap}.opt-btn[data-v-7a18cb78],.btn-run[data-v-7a18cb78],.btn-delete[data-v-7a18cb78],.download[data-v-7a18cb78]{border:none;cursor:pointer;border-radius:7px}.opt-btn[data-v-7a18cb78]{padding:8px 14px;color:#ccc;background:#2a2a2a;border:1px solid #3a3a3a}.btn-run[data-v-7a18cb78]{padding:10px 18px;color:#fff;background:#3498db;font-weight:600}.btn-queue[data-v-7a18cb78]{background:#27ae60}.btn-run[data-v-7a18cb78]:disabled{opacity:.55;cursor:not-allowed}.selected-files[data-v-7a18cb78]{margin-top:14px;color:#999;font-size:12px;word-break:break-all}.selected-files span[data-v-7a18cb78]{display:block;margin:4px 0}.prompt-card[data-v-7a18cb78],.secret-card[data-v-7a18cb78]{margin-bottom:18px}.secret-card[data-v-7a18cb78]{display:none}.prompt-input[data-v-7a18cb78]{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}.secret-input[data-v-7a18cb78]{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[data-v-7a18cb78]:focus,.secret-input[data-v-7a18cb78]:focus{border-color:#3498db}.parse-card[data-v-7a18cb78],.queue-payload[data-v-7a18cb78]{margin-top:14px;padding:12px;border:1px solid #2a2a2a;border-radius:8px;background:#202020;color:#b8c1cc;font-size:12px}.queue-payload[data-v-7a18cb78]{max-height:220px;overflow:auto;color:#8fd3ff;white-space:pre-wrap}.panel-header[data-v-7a18cb78]{padding:16px 20px;border-bottom:1px solid #2a2a2a;font-size:15px;font-weight:600;color:#ddd}.task-list-wrap[data-v-7a18cb78]{flex:1;padding:16px 20px;overflow:auto}.clean-result-summary[data-v-7a18cb78]{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin-bottom:16px}.summary-card[data-v-7a18cb78]{padding:14px 16px;border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e}.summary-card strong[data-v-7a18cb78]{display:block;margin-top:8px;color:#eaf4ff;font-size:22px}.summary-label[data-v-7a18cb78]{color:#8d8d8d;font-size:12px}.result-list-wrap[data-v-7a18cb78]{border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e;min-height:180px;margin:0 0 16px}.result-list-header[data-v-7a18cb78]{display:flex;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #2a2a2a;color:#ddd;font-size:14px}.empty-tasks[data-v-7a18cb78]{color:#666;font-size:13px;padding:18px;text-align:center}.result-table[data-v-7a18cb78]{--el-table-bg-color: #222;--el-table-tr-bg-color: #222;--el-table-header-bg-color: #2a2a2a;--el-table-text-color: #ccc;--el-table-border-color: #333}.task-list[data-v-7a18cb78]{list-style:none;margin:0;padding:12px}.task-item[data-v-7a18cb78]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:12px 14px;border:1px solid #2a2a2a;border-radius:8px;margin-bottom:8px;background:#222}.left[data-v-7a18cb78]{flex:1;min-width:0}.id[data-v-7a18cb78]{color:#e0e0e0;font-size:13px;font-weight:600}.task-right[data-v-7a18cb78]{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.status[data-v-7a18cb78]{padding:4px 10px;border-radius:6px;font-size:12px}.status.success[data-v-7a18cb78]{background:#2ecc712e;color:#2ecc71}.status.failed[data-v-7a18cb78]{background:#e74c3c2e;color:#ff6b6b}.status.running[data-v-7a18cb78]{background:#3498db2e;color:#3498db}.status.pending[data-v-7a18cb78]{background:#95a5a62e;color:#bdc3c7}.result-hint[data-v-7a18cb78]{margin-top:6px;color:#e0b96d}.file-progress[data-v-7a18cb78]{margin-top:8px;max-width:520px}.file-progress-meta[data-v-7a18cb78]{display:flex;justify-content:space-between;gap:12px;color:#d8c278;font-size:12px}.file-progress-track[data-v-7a18cb78]{margin-top:5px;height:8px;border-radius:999px;overflow:hidden;background:#303030;border:1px solid #3b3b3b}.file-progress-bar[data-v-7a18cb78]{height:100%;border-radius:inherit;background:linear-gradient(90deg,#4aa3ff,#f0c75e);transition:width .25s ease}.download[data-v-7a18cb78]{padding:6px 10px;color:#d6ecff;background:#3498db2e}.btn-delete[data-v-7a18cb78]{padding:6px 10px;color:#ff8f8f;background:#e74c3c1f}@media(max-width:1100px){.main-content[data-v-7a18cb78]{flex-direction:column;height:auto}.left-panel[data-v-7a18cb78]{width:100%;border-right:none;border-bottom:1px solid #2a2a2a}.clean-result-summary[data-v-7a18cb78]{grid-template-columns:repeat(2,minmax(0,1fr))}} diff --git a/app/assets/appearance-patent-efxpNAXi.css b/app/assets/appearance-patent-efxpNAXi.css deleted file mode 100644 index ff6ec96..0000000 --- a/app/assets/appearance-patent-efxpNAXi.css +++ /dev/null @@ -1 +0,0 @@ -.module-page[data-v-92ea74a2]{min-height:100vh;background:#1a1a1a}.main-content[data-v-92ea74a2]{display:flex;height:calc(100vh - 56px);min-height:calc(100vh - 56px)}.left-panel[data-v-92ea74a2]{width:400px;background:#1e1e1e;padding:20px;overflow-y:auto;border-right:1px solid #2a2a2a}.right-panel[data-v-92ea74a2]{flex:1;min-width:0;background:#1a1a1a;display:flex;flex-direction:column}.section-title[data-v-92ea74a2],.subsection-title[data-v-92ea74a2]{font-size:13px;color:#bbb;margin-bottom:10px}.upload-zone[data-v-92ea74a2]{border:1px dashed #3a3a3a;border-radius:10px;padding:18px;background:#252525;margin-bottom:18px}.hint[data-v-92ea74a2],.loading-msg[data-v-92ea74a2],.files[data-v-92ea74a2],.muted[data-v-92ea74a2]{color:#888;font-size:12px;line-height:1.5}.link[data-v-92ea74a2]{color:#6ea8fe;text-decoration:none}.link[data-v-92ea74a2]:hover{color:#9fc5ff}.btns[data-v-92ea74a2],.run-row[data-v-92ea74a2]{display:flex;gap:10px;flex-wrap:wrap}.opt-btn[data-v-92ea74a2],.btn-run[data-v-92ea74a2],.btn-delete[data-v-92ea74a2],.download[data-v-92ea74a2]{border:none;cursor:pointer;border-radius:7px}.opt-btn[data-v-92ea74a2]{padding:8px 14px;color:#ccc;background:#2a2a2a;border:1px solid #3a3a3a}.btn-run[data-v-92ea74a2]{padding:10px 18px;color:#fff;background:#3498db;font-weight:600}.btn-queue[data-v-92ea74a2]{background:#27ae60}.btn-run[data-v-92ea74a2]:disabled{opacity:.55;cursor:not-allowed}.selected-files[data-v-92ea74a2]{margin-top:14px;color:#999;font-size:12px;word-break:break-all}.selected-files span[data-v-92ea74a2]{display:block;margin:4px 0}.prompt-card[data-v-92ea74a2],.secret-card[data-v-92ea74a2]{margin-bottom:18px}.secret-card[data-v-92ea74a2]{display:none}.prompt-input[data-v-92ea74a2]{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}.secret-input[data-v-92ea74a2]{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[data-v-92ea74a2]:focus,.secret-input[data-v-92ea74a2]:focus{border-color:#3498db}.parse-card[data-v-92ea74a2],.queue-payload[data-v-92ea74a2]{margin-top:14px;padding:12px;border:1px solid #2a2a2a;border-radius:8px;background:#202020;color:#b8c1cc;font-size:12px}.queue-payload[data-v-92ea74a2]{max-height:220px;overflow:auto;color:#8fd3ff;white-space:pre-wrap}.panel-header[data-v-92ea74a2]{padding:16px 20px;border-bottom:1px solid #2a2a2a;font-size:15px;font-weight:600;color:#ddd}.task-list-wrap[data-v-92ea74a2]{flex:1;padding:16px 20px;overflow:auto}.clean-result-summary[data-v-92ea74a2]{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin-bottom:16px}.summary-card[data-v-92ea74a2]{padding:14px 16px;border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e}.summary-card strong[data-v-92ea74a2]{display:block;margin-top:8px;color:#eaf4ff;font-size:22px}.summary-label[data-v-92ea74a2]{color:#8d8d8d;font-size:12px}.result-list-wrap[data-v-92ea74a2]{border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e;min-height:180px;margin:0 0 16px}.result-list-header[data-v-92ea74a2]{display:flex;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #2a2a2a;color:#ddd;font-size:14px}.empty-tasks[data-v-92ea74a2]{color:#666;font-size:13px;padding:18px;text-align:center}.result-table[data-v-92ea74a2]{--el-table-bg-color: #222;--el-table-tr-bg-color: #222;--el-table-header-bg-color: #2a2a2a;--el-table-text-color: #ccc;--el-table-border-color: #333}.task-list[data-v-92ea74a2]{list-style:none;margin:0;padding:12px}.task-item[data-v-92ea74a2]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:12px 14px;border:1px solid #2a2a2a;border-radius:8px;margin-bottom:8px;background:#222}.left[data-v-92ea74a2]{flex:1;min-width:0}.id[data-v-92ea74a2]{color:#e0e0e0;font-size:13px;font-weight:600}.task-right[data-v-92ea74a2]{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.status[data-v-92ea74a2]{padding:4px 10px;border-radius:6px;font-size:12px}.status.success[data-v-92ea74a2]{background:#2ecc712e;color:#2ecc71}.status.failed[data-v-92ea74a2]{background:#e74c3c2e;color:#ff6b6b}.status.running[data-v-92ea74a2]{background:#3498db2e;color:#3498db}.status.pending[data-v-92ea74a2]{background:#95a5a62e;color:#bdc3c7}.result-hint[data-v-92ea74a2]{margin-top:6px;color:#e0b96d}.file-progress[data-v-92ea74a2]{margin-top:8px;max-width:520px}.file-progress-meta[data-v-92ea74a2]{display:flex;justify-content:space-between;gap:12px;color:#d8c278;font-size:12px}.file-progress-track[data-v-92ea74a2]{margin-top:5px;height:8px;border-radius:999px;overflow:hidden;background:#303030;border:1px solid #3b3b3b}.file-progress-bar[data-v-92ea74a2]{height:100%;border-radius:inherit;background:linear-gradient(90deg,#4aa3ff,#f0c75e);transition:width .25s ease}.download[data-v-92ea74a2]{padding:6px 10px;color:#d6ecff;background:#3498db2e}.btn-delete[data-v-92ea74a2]{padding:6px 10px;color:#ff8f8f;background:#e74c3c1f}@media(max-width:1100px){.main-content[data-v-92ea74a2]{flex-direction:column;height:auto}.left-panel[data-v-92ea74a2]{width:100%;border-right:none;border-bottom:1px solid #2a2a2a}.clean-result-summary[data-v-92ea74a2]{grid-template-columns:repeat(2,minmax(0,1fr))}} diff --git a/app/assets/appearance-patent.js b/app/assets/appearance-patent.js index 865f72c..8670139 100644 --- a/app/assets/appearance-patent.js +++ b/app/assets/appearance-patent.js @@ -1 +1 @@ -import{d as Le,o as Ke,M as Je,a as i,c,b as qe,B as je,e as a,F as se,r as te,t as r,w as Oe,H as Ve,f as I,O as ge,n as We,g as v,h as q,i as j,E as p,W as Ye,X as Qe,Y as Xe,V as he,Z as Ze,$ as es,a0 as ss,s as ts,a1 as as,a2 as ns,a3 as ls,a4 as rs,_ as os,q as us,u as is}from"./java-modules-DzYrjxib.js";import{e as cs}from"./brand-jr47vQUd.js";import{c as ds}from"./categorized-timers-JPA-olTr.js";const fs={class:"page-shell module-page"},ps={class:"main-content"},vs={class:"left-panel"},gs={class:"upload-zone"},hs={class:"selected-files"},ys={key:0},ks={class:"prompt-card"},Is={class:"run-row"},_s=["disabled"],Ps=["disabled"],ws={key:0,class:"parse-card"},Cs={key:1,class:"queue-payload"},Ss={class:"right-panel"},bs={class:"task-list-wrap"},ms={class:"clean-result-summary"},Ns={class:"summary-card"},Fs={class:"summary-card"},Ts={class:"summary-card"},Rs={class:"summary-card"},As={class:"result-list-wrap"},Es={key:0,class:"empty-tasks"},xs={key:1,class:"task-list clean-result-list"},Us={class:"left"},Ds={class:"id"},$s={class:"files"},Ms={class:"files"},zs={class:"files"},Gs={class:"files"},Bs={key:0,class:"files result-hint"},Hs={key:1,class:"file-progress"},Ls={class:"file-progress-meta"},Ks={class:"file-progress-track"},Js={class:"task-right"},qs={class:"status running"},js=["onClick"],Os={class:"result-list-wrap"},Vs={key:0,class:"empty-tasks"},Ws={key:1,class:"task-list clean-result-list"},Ys={class:"left"},Qs={class:"id"},Xs={class:"files"},Zs={class:"files"},et={class:"files"},st={key:0,class:"files"},tt={key:1,class:"files result-hint"},at={key:2,class:"file-progress"},nt={class:"file-progress-meta"},lt={class:"file-progress-track"},rt={key:3,class:"files"},ot={class:"task-right"},ut=["onClick"],it=["onClick"],ct=3e3,dt=Le({__name:"BrandAppearancePatentTab",setup(pt){const D=v([]),F=v([]),P=v(null),T=v(null),$=v(""),M=v(!1),z=v(!1),C=v(""),f=v([]),u=v([]),h=v(null),O=v(!1);let R=null,ae=0,A=!1;const E=ds("appearance-patent"),x=v({pendingTaskCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),g=v([]),w=v({}),b=q(()=>P.value||T.value),V=q(()=>{const e=P.value;return!e?.taskId||g.value.some(t=>t.taskId===e.taskId)?null:{taskId:e.taskId,sourceFilename:e.sourceFilename,rowCount:e.acceptedRows,taskStatus:"PENDING",success:!1}}),ne=q(()=>{const e=new Set([...f.value,...u.value]),s=g.value.filter(n=>{const l=k(n);return n.taskId!=null&&(e.has(n.taskId)||l==="RUNNING"||l==="PENDING")}).map(n=>re(n));for(const[n,l]of Object.entries(w.value)){const o=Number(n);!Number.isFinite(o)||o<=0||!e.has(o)&&k(l)!=="RUNNING"&&k(l)!=="PENDING"||s.some(d=>d.taskId===o)||s.push(re(l))}return V.value?s.some(n=>n.taskId===V.value?.taskId)?s:[V.value,...s]:s}),le=q(()=>g.value.filter(e=>{const s=k(e);return s!=="RUNNING"&&s!=="PENDING"}));function re(e){if(e.taskId==null)return e;const s=w.value[e.taskId];return s?{...e,...s,sourceFilename:s.sourceFilename||e.sourceFilename,resultFilename:s.resultFilename||e.resultFilename,rowCount:s.rowCount??e.rowCount,createdAt:s.createdAt||e.createdAt}:e}function ye(){return $.value.trim()}function ke(){return $.value.trim()}function G(){return ls("appearance-patent").trim()}function Ie(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function W(){return`appearance-patent:tasks:${Ie()}`}function _e(e){return{taskId:e.taskId,totalRows:e.totalRows,acceptedRows:e.acceptedRows,groupCount:e.groupCount,droppedRows:e.droppedRows}}function S(){if(typeof window>"u")return;const e=Array.from(new Set([...f.value,...u.value]));e.length?window.localStorage.setItem(W(),JSON.stringify(e)):window.localStorage.removeItem(W())}function Pe(){if(!(typeof window>"u"))try{const e=window.localStorage.getItem(W()),s=e?JSON.parse(e):[];f.value=Array.isArray(s)?s.filter(t=>typeof t=="number"&&t>0):[]}catch{f.value=[]}}function B(e){if(!e)return"-";const s=new Date(e);if(Number.isNaN(s.getTime()))return e;const t=s.getFullYear(),n=String(s.getMonth()+1).padStart(2,"0"),l=String(s.getDate()).padStart(2,"0"),o=String(s.getHours()).padStart(2,"0"),d=String(s.getMinutes()).padStart(2,"0"),y=String(s.getSeconds()).padStart(2,"0");return`${t}-${n}-${l} ${o}:${d}:${y}`}async function oe(e){const s=j();if(!s?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传能力");const t=[];for(const n of e){const l=typeof n=="string"?n:n.absolutePath,o=typeof n=="string"?void 0:n.relativePath,d=await s.upload_file_to_java(l,o);if(!d?.success||!d.data)throw new Error(d?.error||d?.message||`上传失败:${l}`);t.push(d.data)}return t}async function we(){const e=j();if(!e?.select_brand_xlsx_files||!e.upload_file_to_java){p.warning("当前环境不支持文件选择或上传");return}const s=await e.select_brand_xlsx_files();if(!s?.length)return;const t=await oe(s);F.value=t,D.value=t.map(n=>n.relativePath||n.originalFilename||n.fileKey),P.value=null,T.value=null,C.value=""}async function Ce(){const e=j();if(!e?.select_brand_folder){p.warning("当前环境不支持文件夹选择,请在本地客户端中打开");return}try{const s=await e.select_brand_folder();if(!s)return;const t=await cs(s);if(!t.success||!t.items?.length){p.warning(t.error||"该文件夹下没有可用的 xlsx 文件");return}const n=await oe(t.items);F.value=n,D.value=t.items.map(l=>l.relativePath||l.absolutePath),P.value=null,T.value=null,C.value="",p.success(`已选择文件夹内 ${t.items.length} 个 Excel 文件`)}catch(s){p.error(s instanceof Error?s.message:"选择失败")}}async function Se(){if(!F.value.length){p.warning("请先选择 Excel");return}if(!G()){p.warning("请先在左上角设置中填写外观专利密钥");return}M.value=!0;try{const e=F.value.map(t=>({fileKey:t.fileKey,originalFilename:t.originalFilename,relativePath:t.relativePath})),s=await Ye(e,ye(),G());P.value=s,T.value=null,C.value="",p.success(`解析完成,共 ${s.groupCount||0} 组 / ${s.acceptedRows} 条`)}catch(e){p.error(e instanceof Error?e.message:"解析失败")}finally{M.value=!1}}async function be(){const e=j(),s=P.value,t=s?.taskId;if(!t){p.warning("请先解析文件");return}if(!e?.enqueue_json){p.error("当前环境未启用 pywebview enqueue_json");return}if(!G()){p.warning("请先在左上角设置中填写外观专利密钥");return}z.value=!0;try{const l=(await Qe(t)).groups||[],o={type:"appearance-patent-run",ts:Date.now(),data:{taskId:t,prompt:ke(),api_key:G(),sourceFileCount:s.sourceFileCount||0,totalRows:s.totalRows||0,acceptedRows:s.acceptedRows||0,groupCount:s.groupCount||0,groups:l.map(y=>({sourceFileKey:y.sourceFileKey||"",sourceFilename:y.sourceFilename||"",groupKey:y.groupKey||"",baseId:y.baseId||"",displayId:y.displayId||"",items:(y.items||[]).map(_=>({sourceFileKey:_.sourceFileKey||"",sourceFilename:_.sourceFilename||"",rowToken:_.rowToken||"",groupKey:_.groupKey||"",id:_.displayId,asin:_.asin,country:_.country,url:_.url||"",title:_.title||""}))}))}};C.value=`任务 ${t} 已准备推送,共 ${l.length} 组`,await Xe(t);const d=await e.enqueue_json(o);if(!d?.success){p.error(d?.error||"推送失败");return}T.value=_e(s),Ne(t),me(),await H(),await L({force:!0}),p.success("已推送到 Python 队列")}finally{z.value=!1}}function me(){P.value=null,C.value=""}function Ne(e){f.value.includes(e)||(f.value=[...f.value,e],S()),m()}function Y(e){if(f.value=f.value.filter(s=>s!==e),!u.value.includes(e)){const s={...w.value};delete s[e],w.value=s}S()}function Fe(e){u.value.includes(e)||(u.value=[...u.value,e],S()),m()}function Q(e){if(u.value=u.value.filter(s=>s!==e),!f.value.includes(e)){const s={...w.value};delete s[e],w.value=s}S()}function m(){A||h.value==null&&Te(!0)}function ue(){h.value!=null&&(E.clearTimer("task-poll",h.value),h.value=null)}function Te(e=!1){if(A)return;if(h.value!=null){if(!e)return;E.clearTimer("task-poll",h.value),h.value=null}const s=async()=>{h.value=null,!A&&(!f.value.length&&!u.value.length||(await Re(),!A&&h.value==null&&(f.value.length||u.value.length)&&(h.value=E.setTimeout("task-poll",s,he()))))};e?s():h.value=E.setTimeout("task-poll",s,he())}async function Re(){if(O.value||!f.value.length&&!u.value.length){!f.value.length&&!u.value.length&&ue();return}O.value=!0;try{let e=!1,s=!1;const t=Array.from(new Set([...f.value,...u.value]));if(t.length){const n=await rs(t,{force:u.value.length>0});for(const l of n.items||[]){const o=l.task;if(!o?.id)continue;const d=l.items?.[0];if(d&&(w.value={...w.value,[o.id]:d},Ae(d)),(o.status==="SUCCESS"||o.status==="FAILED")&&(Y(o.id),e=!0,o.status==="SUCCESS"?Fe(o.id):Q(o.id)),d&&o.status==="SUCCESS"&&u.value.includes(o.id)){const y=(d.fileStatus||"").toUpperCase();(d.fileReady||y==="SUCCESS"||y==="FAILED")&&(Q(o.id),e=!0,s=!0)}}n.missingTaskIds?.length&&(n.missingTaskIds.forEach(l=>{Y(l),Q(l)}),s=!0,e=!0)}e&&await H(),s&&await L(),Ee()}finally{O.value=!1}}function Ae(e){if(!e.taskId&&!e.resultId)return;const s=g.value.findIndex(t=>e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId);s>=0?g.value[s]={...g.value[s],...e}:g.value=[e,...g.value]}function Ee(){if(!u.value.length)return;const e=[];for(const s of u.value){const t=g.value.find(o=>o.taskId===s);if(!t){e.push(s);continue}const n=(t.taskStatus||"").toUpperCase(),l=(t.fileStatus||"").toUpperCase();n==="FAILED"||t.fileReady||l==="SUCCESS"||l==="FAILED"||n==="SUCCESS"&&e.push(s)}u.value=e,S(),u.value.length&&m()}function xe(){const e=g.value.filter(s=>s.taskId!=null&&N(s)).map(s=>s.taskId);u.value=Array.from(new Set(e)),S(),u.value.length&&m()}function Ue(){const e=g.value.filter(s=>s.taskId!=null&&k(s)==="RUNNING").map(s=>s.taskId);e.length&&(f.value=Array.from(new Set([...f.value,...e])),S(),m())}async function H(){x.value=await Ze()}async function L(e={}){const s=Date.now();if(!(!e.force&&g.value.length&&s-ae{g.value=De(g.value,t.items||[]),ae=Date.now()}).finally(()=>{R=null}),R)}function De(e,s){const t=new Map,n=new Map;for(const l of e||[])l.taskId!=null&&t.set(l.taskId,l),l.resultId!=null&&n.set(l.resultId,l);return(s||[]).map(l=>{const o=l.resultId!=null?n.get(l.resultId):l.taskId!=null?t.get(l.taskId):void 0;return $e(o,l)})}function $e(e,s){return!e||!((k(e)==="RUNNING"||N(e)||U(e))&&!U(s)&&!ee(s))?s:{...s,fileJobId:s.fileJobId??e.fileJobId,fileStatus:s.fileStatus||e.fileStatus,fileError:s.fileError||e.fileError,fileReady:s.fileReady||e.fileReady,fileProgressPercent:X(s.fileProgressPercent)?s.fileProgressPercent:e.fileProgressPercent,fileProgressCurrent:X(s.fileProgressCurrent)?s.fileProgressCurrent:e.fileProgressCurrent,fileProgressTotal:X(s.fileProgressTotal)?s.fileProgressTotal:e.fileProgressTotal,fileProgressMessage:(s.fileProgressMessage||"").trim()?s.fileProgressMessage:e.fileProgressMessage}}function X(e){const s=Number(e);return Number.isFinite(s)&&s>0}function ie(e){const s=k(e);return s==="RUNNING"?"执行中":s==="PENDING"?"已解析待推送":N(e)?"结果生成中":Z(e)?"结果生成失败":s==="SUCCESS"||e.success?"已完成":s==="FAILED"?"失败":"等待中"}function Me(e){const s=k(e);return s==="RUNNING"||N(e)?"running":Z(e)||s==="FAILED"?"failed":s==="SUCCESS"||e.success?"success":"pending"}function N(e){const s=k(e),t=(e.fileStatus||"").toUpperCase();return!(s!=="SUCCESS"||ee(e)||t==="FAILED"||t==="SUCCESS")}function k(e){return(e.taskStatus||"").toUpperCase()}function Z(e){return(e.fileStatus||"").toUpperCase()==="FAILED"}function K(e){if(Z(e))return e.fileError||"结果文件生成失败,请稍后重试或检查后端日志";if(U(e)||!N(e))return"";const s=(e.fileStatus||"").toUpperCase();return s==="RUNNING"?"任务已完成,正在等待 Coze 回流并组装结果文件,下载按钮稍后出现":s==="PENDING"?"任务已完成,结果文件已入队,正在等待后端开始处理":"任务已完成,正在生成结果文件,下载按钮稍后出现"}function ee(e){return!!(e.resultId&&(e.fileReady||e.downloadUrl))}function J(e){const s=Number(e.fileProgressPercent||0);return Number.isFinite(s)&&s>0?Math.max(0,Math.min(100,Math.round(s))):pe(e)?fe(e)==="PENDING"?6:10:0}function ce(e,s){const t=(e.fileProgressMessage||"").trim();return t?ze(t):s}function ze(e){const s=e.match(/^Coze submitted (\d+) batches, completed (\d+), waiting for results$/);if(s)return`已提交 Coze ${s[1]} 批,已完成 ${s[2]} 批,等待结果回流`;const t=e.match(/^Coze completed (\d+) batches, waiting for remaining Python data$/);return t?`Coze 已完成 ${t[1]} 批,等待 Python 继续回传数据`:{"Receiving Python data, waiting for 50 rows before Coze":"正在接收 Python 数据,累计 50 条后提交 Coze","Submitting Coze":"正在提交 Coze","Coze submitted, waiting for result":"Coze 已提交,等待结果回流","Waiting for Python upload":"等待 Python 继续回传数据","Coze results ready, assembling xlsx":"Coze 结果已回流,正在组装 xlsx","Assembling xlsx":"正在组装 xlsx","Uploading result file":"正在上传结果文件","Result file generated":"结果文件已生成"}[e]||e}function U(e){return(k(e)==="RUNNING"||N(e))&&(de(e)||pe(e))}function de(e){return Ge(e)||Number(e.fileProgressPercent||0)>0||!!(e.fileProgressMessage||"").trim()}function Ge(e){return(e.fileProgressTotal||0)>0}function fe(e){return(e.fileStatus||"").toUpperCase()}function Be(e){const s=fe(e);return e.fileJobId!=null||s==="PENDING"||s==="RUNNING"}function pe(e){return Be(e)&&!de(e)}async function He(e){if(!e.resultId)return;const s=e.downloadUrl||ss(e.resultId),t=e.resultFilename||`${e.sourceFilename||"appearance-patent"}.xlsx`,n=await ts(s,t,`appearance-patent:${e.resultId}`);n.success?p.success(`已保存: ${n.path||t}`):n.error&&n.error!=="用户取消"&&p.error(n.error)}async function ve(e){try{e.taskStatus==="RUNNING"&&e.taskId?(await as(e.taskId),Y(e.taskId)):e.resultId&&await ns(e.resultId),await H(),await L({force:!0}),p.success("已删除")}catch(s){p.error(s instanceof Error?s.message:"删除失败")}}return Ke(async()=>{Pe(),await Promise.all([H().catch(()=>{}),L().catch(()=>{})]),Ue(),xe(),(f.value.length||u.value.length)&&m()}),Je(()=>{A=!0,ue(),E.clearScope()}),(e,s)=>(i(),c("div",fs,[qe(je,{active:"appearance-patent"}),a("div",ps,[a("aside",vs,[s[3]||(s[3]=a("div",{class:"section-title"},"上传文件",-1)),a("div",gs,[s[1]||(s[1]=a("div",{class:"hint"},"选择 Excel 后点击解析,后端会提取 id、ASIN、国家,并保留整数 id 与子数据的第一条。",-1)),a("div",{class:"btns"},[a("button",{type:"button",class:"opt-btn",onClick:we},"选择 Excel"),a("button",{type:"button",class:"opt-btn",onClick:Ce},"选择文件夹")]),a("div",hs,[D.value.length?(i(!0),c(se,{key:1},te(D.value,t=>(i(),c("span",{key:t},r(t),1))),128)):(i(),c("span",ys,"暂未选择文件"))])]),a("div",ks,[s[2]||(s[2]=a("div",{class:"section-title"},"新增条件要求",-1)),Oe(a("textarea",{"onUpdate:modelValue":s[0]||(s[0]=t=>$.value=t),class:"prompt-input",rows:"8",placeholder:"可选,留空则不向 Coze 传 prompt 字段;填写后将作为 prompt 透传"},null,512),[[Ve,$.value]])]),a("div",Is,[a("button",{type:"button",class:"btn-run",disabled:M.value||!F.value.length,onClick:Se},r(M.value?"解析中...":"解析并创建任务"),9,_s),a("button",{type:"button",class:"btn-run btn-queue",disabled:z.value||!P.value?.taskId,onClick:be},r(z.value?"推送中...":"推送到 Python 队列"),9,Ps)]),s[4]||(s[4]=a("p",{class:"loading-msg"},"Python 回传字段按 asin、国家、url、标题提交;后端接收分片后累计 50 条调用 Coze,当前任务区展示 Coze 回流和结果组装进度。",-1)),b.value?(i(),c("div",ws,[a("div",null,"任务 ID:"+r(b.value.taskId),1),a("div",null,"总行数:"+r(b.value.totalRows)+",有效:"+r(b.value.acceptedRows)+",分组:"+r(b.value.groupCount||0)+",过滤:"+r(b.value.droppedRows),1)])):I("",!0),C.value?(i(),c("pre",Cs,r(C.value),1)):I("",!0)]),a("section",Ss,[s[12]||(s[12]=a("div",{class:"panel-header"},"外观专利检测",-1)),a("div",bs,[a("div",ms,[a("div",Ns,[s[5]||(s[5]=a("span",{class:"summary-label"},"运行中任务",-1)),a("strong",null,r(x.value.pendingTaskCount),1)]),a("div",Fs,[s[6]||(s[6]=a("span",{class:"summary-label"},"已结束任务",-1)),a("strong",null,r(x.value.processedTaskCount),1)]),a("div",Ts,[s[7]||(s[7]=a("span",{class:"summary-label"},"成功任务",-1)),a("strong",null,r(x.value.successTaskCount),1)]),a("div",Rs,[s[8]||(s[8]=a("span",{class:"summary-label"},"失败任务",-1)),a("strong",null,r(x.value.failedTaskCount),1)])]),s[11]||(s[11]=a("div",{class:"subsection-title"},"匹配任务",-1)),a("div",As,[s[9]||(s[9]=a("div",{class:"result-list-header"},[a("span",null,"当前任务")],-1)),ne.value.length?(i(),c("ul",xs,[(i(!0),c(se,null,te(ne.value,t=>(i(),c("li",{key:`cur-${t.taskId}`,class:"task-item"},[a("div",Us,[a("span",Ds,r(t.sourceFilename||"外观专利检测"),1),a("div",$s,"任务 ID:"+r(t.taskId),1),a("div",Ms,"开始时间:"+r(B(t.startedAt||t.createdAt)),1),a("div",zs,"结束时间:"+r(B(t.finishedAt)),1),a("div",Gs,"行数:"+r(t.rowCount??"-"),1),K(t)?(i(),c("div",Bs,r(K(t)),1)):I("",!0),U(t)?(i(),c("div",Hs,[a("div",Ls,[a("span",null,r(ce(t,"处理中")),1),a("span",null,r(J(t))+"%",1)]),a("div",Ks,[a("div",{class:"file-progress-bar",style:ge({width:`${J(t)}%`})},null,4)])])):I("",!0)]),a("div",Js,[a("span",qs,r(ie(t)),1),a("button",{type:"button",class:"btn-delete",onClick:n=>ve(t)},"删除",8,js)])]))),128))])):(i(),c("div",Es,"暂无当前任务"))]),a("div",Os,[s[10]||(s[10]=a("div",{class:"result-list-header"},[a("span",null,"历史记录")],-1)),le.value.length?(i(),c("ul",Ws,[(i(!0),c(se,null,te(le.value,t=>(i(),c("li",{key:`his-${t.resultId}-${t.taskId}`,class:"task-item"},[a("div",Ys,[a("span",Qs,r(t.sourceFilename||"外观专利检测"),1),a("div",Xs,"任务 ID:"+r(t.taskId??"-"),1),a("div",Zs,"开始时间:"+r(B(t.startedAt||t.createdAt)),1),a("div",et,"结束时间:"+r(B(t.finishedAt)),1),t.resultFilename?(i(),c("div",st,r(t.resultFilename||"下载结果"),1)):I("",!0),K(t)?(i(),c("div",tt,r(K(t)),1)):I("",!0),U(t)?(i(),c("div",at,[a("div",nt,[a("span",null,r(ce(t,"结果生成中")),1),a("span",null,r(J(t))+"%",1)]),a("div",lt,[a("div",{class:"file-progress-bar",style:ge({width:`${J(t)}%`})},null,4)])])):I("",!0),t.error?(i(),c("div",rt,"错误:"+r(t.error),1)):I("",!0)]),a("div",ot,[a("span",{class:We(["status",Me(t)])},r(ie(t)),3),ee(t)?(i(),c("button",{key:0,type:"button",class:"download",onClick:n=>He(t)},"下载",8,ut)):I("",!0),t.resultId?(i(),c("button",{key:1,type:"button",class:"btn-delete",onClick:n=>ve(t)},"删除",8,it)):I("",!0)])]))),128))])):(i(),c("div",Vs,"暂无历史记录"))])])])])]))}}),ft=os(dt,[["__scopeId","data-v-92ea74a2"]]);us(ft).use(is).mount("#app"); +import{d as Le,o as Ke,M as Je,a as i,c,b as qe,B as je,e as a,F as se,r as te,t as r,w as Oe,H as Ve,f as _,O as ge,n as We,g as v,h as q,i as j,E as p,W as Ye,X as Qe,Y as Xe,V as he,Z as Ze,$ as es,a0 as ss,s as ts,a1 as as,a2 as ns,a3 as ls,a4 as rs,_ as os,q as us,u as is}from"./java-modules-B8c-YG5x.js";import{e as cs}from"./brand-COze15GJ.js";import{c as ds}from"./categorized-timers-JPA-olTr.js";const fs={class:"page-shell module-page"},ps={class:"main-content"},vs={class:"left-panel"},gs={class:"upload-zone"},hs={class:"selected-files"},ys={key:0},ks={class:"prompt-card"},Is={class:"run-row"},_s=["disabled"],Ps=["disabled"],ws={key:0,class:"parse-card"},Cs={key:1,class:"queue-payload"},Ss={class:"right-panel"},bs={class:"task-list-wrap"},ms={class:"clean-result-summary"},Ns={class:"summary-card"},Fs={class:"summary-card"},Ts={class:"summary-card"},Rs={class:"summary-card"},As={class:"result-list-wrap"},Es={key:0,class:"empty-tasks"},xs={key:1,class:"task-list clean-result-list"},Us={class:"left"},Ds={class:"id"},$s={class:"files"},Ms={class:"files"},zs={class:"files"},Gs={class:"files"},Bs={key:0,class:"files result-hint"},Hs={key:1,class:"file-progress"},Ls={class:"file-progress-meta"},Ks={class:"file-progress-track"},Js={class:"task-right"},qs={class:"status running"},js=["onClick"],Os={class:"result-list-wrap"},Vs={key:0,class:"empty-tasks"},Ws={key:1,class:"task-list clean-result-list"},Ys={class:"left"},Qs={class:"id"},Xs={class:"files"},Zs={class:"files"},et={class:"files"},st={key:0,class:"files"},tt={key:1,class:"files result-hint"},at={key:2,class:"file-progress"},nt={class:"file-progress-meta"},lt={class:"file-progress-track"},rt={key:3,class:"files"},ot={class:"task-right"},ut=["onClick"],it=["onClick"],ct=3e3,dt=Le({__name:"BrandAppearancePatentTab",setup(pt){const D=v([]),F=v([]),P=v(null),T=v(null),$=v(""),M=v(!1),z=v(!1),C=v(""),f=v([]),u=v([]),h=v(null),O=v(!1);let R=null,ae=0,A=!1;const E=ds("appearance-patent"),x=v({pendingTaskCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),g=v([]),w=v({}),b=q(()=>P.value||T.value),V=q(()=>{const e=P.value;return!e?.taskId||g.value.some(t=>t.taskId===e.taskId)?null:{taskId:e.taskId,sourceFilename:e.sourceFilename,rowCount:e.acceptedRows,taskStatus:"PENDING",success:!1}}),ne=q(()=>{const e=new Set([...f.value,...u.value]),s=g.value.filter(n=>{const l=k(n);return n.taskId!=null&&(e.has(n.taskId)||l==="RUNNING"||l==="PENDING")}).map(n=>re(n));for(const[n,l]of Object.entries(w.value)){const o=Number(n);!Number.isFinite(o)||o<=0||!e.has(o)&&k(l)!=="RUNNING"&&k(l)!=="PENDING"||s.some(d=>d.taskId===o)||s.push(re(l))}return V.value?s.some(n=>n.taskId===V.value?.taskId)?s:[V.value,...s]:s}),le=q(()=>g.value.filter(e=>{const s=k(e);return s!=="RUNNING"&&s!=="PENDING"}));function re(e){if(e.taskId==null)return e;const s=w.value[e.taskId];return s?{...e,...s,sourceFilename:s.sourceFilename||e.sourceFilename,resultFilename:s.resultFilename||e.resultFilename,rowCount:s.rowCount??e.rowCount,createdAt:s.createdAt||e.createdAt}:e}function ye(){return $.value.trim()}function ke(){return $.value.trim()}function G(){return ls("appearance-patent").trim()}function Ie(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function W(){return`appearance-patent:tasks:${Ie()}`}function _e(e){return{taskId:e.taskId,totalRows:e.totalRows,acceptedRows:e.acceptedRows,groupCount:e.groupCount,droppedRows:e.droppedRows}}function S(){if(typeof window>"u")return;const e=Array.from(new Set([...f.value,...u.value]));e.length?window.localStorage.setItem(W(),JSON.stringify(e)):window.localStorage.removeItem(W())}function Pe(){if(!(typeof window>"u"))try{const e=window.localStorage.getItem(W()),s=e?JSON.parse(e):[];f.value=Array.isArray(s)?s.filter(t=>typeof t=="number"&&t>0):[]}catch{f.value=[]}}function B(e){if(!e)return"-";const s=new Date(e);if(Number.isNaN(s.getTime()))return e;const t=s.getFullYear(),n=String(s.getMonth()+1).padStart(2,"0"),l=String(s.getDate()).padStart(2,"0"),o=String(s.getHours()).padStart(2,"0"),d=String(s.getMinutes()).padStart(2,"0"),y=String(s.getSeconds()).padStart(2,"0");return`${t}-${n}-${l} ${o}:${d}:${y}`}async function oe(e){const s=j();if(!s?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传能力");const t=[];for(const n of e){const l=typeof n=="string"?n:n.absolutePath,o=typeof n=="string"?void 0:n.relativePath,d=await s.upload_file_to_java(l,o);if(!d?.success||!d.data)throw new Error(d?.error||d?.message||`上传失败:${l}`);t.push(d.data)}return t}async function we(){const e=j();if(!e?.select_brand_xlsx_files||!e.upload_file_to_java){p.warning("当前环境不支持文件选择或上传");return}const s=await e.select_brand_xlsx_files();if(!s?.length)return;const t=await oe(s);F.value=t,D.value=t.map(n=>n.relativePath||n.originalFilename||n.fileKey),P.value=null,T.value=null,C.value=""}async function Ce(){const e=j();if(!e?.select_brand_folder){p.warning("当前环境不支持文件夹选择,请在本地客户端中打开");return}try{const s=await e.select_brand_folder();if(!s)return;const t=await cs(s);if(!t.success||!t.items?.length){p.warning(t.error||"该文件夹下没有可用的 xlsx 文件");return}const n=await oe(t.items);F.value=n,D.value=t.items.map(l=>l.relativePath||l.absolutePath),P.value=null,T.value=null,C.value="",p.success(`已选择文件夹内 ${t.items.length} 个 Excel 文件`)}catch(s){p.error(s instanceof Error?s.message:"选择失败")}}async function Se(){if(!F.value.length){p.warning("请先选择 Excel");return}if(!G()){p.warning("请先在左上角设置中填写外观专利密钥");return}M.value=!0;try{const e=F.value.map(t=>({fileKey:t.fileKey,originalFilename:t.originalFilename,relativePath:t.relativePath})),s=await Ye(e,ye(),G());P.value=s,T.value=null,C.value="",p.success(`解析完成,共 ${s.groupCount||0} 组 / ${s.acceptedRows} 条`)}catch(e){p.error(e instanceof Error?e.message:"解析失败")}finally{M.value=!1}}async function be(){const e=j(),s=P.value,t=s?.taskId;if(!t){p.warning("请先解析文件");return}if(!e?.enqueue_json){p.error("当前环境未启用 pywebview enqueue_json");return}if(!G()){p.warning("请先在左上角设置中填写外观专利密钥");return}z.value=!0;try{const l=(await Qe(t)).groups||[],o={type:"appearance-patent-run",ts:Date.now(),data:{taskId:t,prompt:ke(),api_key:G(),sourceFileCount:s.sourceFileCount||0,totalRows:s.totalRows||0,acceptedRows:s.acceptedRows||0,groupCount:s.groupCount||0,groups:l.map(y=>({sourceFileKey:y.sourceFileKey||"",sourceFilename:y.sourceFilename||"",groupKey:y.groupKey||"",baseId:y.baseId||"",displayId:y.displayId||"",items:(y.items||[]).map(I=>({sourceFileKey:I.sourceFileKey||"",sourceFilename:I.sourceFilename||"",rowToken:I.rowToken||"",groupKey:I.groupKey||"",id:I.displayId,asin:I.asin,country:I.country,sku:I.sku||"",url:I.url||"",title:I.title||""}))}))}};C.value=`任务 ${t} 已准备推送,共 ${l.length} 组`,await Xe(t);const d=await e.enqueue_json(o);if(!d?.success){p.error(d?.error||"推送失败");return}T.value=_e(s),Ne(t),me(),await H(),await L({force:!0}),p.success("已推送到 Python 队列")}finally{z.value=!1}}function me(){P.value=null,C.value=""}function Ne(e){f.value.includes(e)||(f.value=[...f.value,e],S()),m()}function Y(e){if(f.value=f.value.filter(s=>s!==e),!u.value.includes(e)){const s={...w.value};delete s[e],w.value=s}S()}function Fe(e){u.value.includes(e)||(u.value=[...u.value,e],S()),m()}function Q(e){if(u.value=u.value.filter(s=>s!==e),!f.value.includes(e)){const s={...w.value};delete s[e],w.value=s}S()}function m(){A||h.value==null&&Te(!0)}function ue(){h.value!=null&&(E.clearTimer("task-poll",h.value),h.value=null)}function Te(e=!1){if(A)return;if(h.value!=null){if(!e)return;E.clearTimer("task-poll",h.value),h.value=null}const s=async()=>{h.value=null,!A&&(!f.value.length&&!u.value.length||(await Re(),!A&&h.value==null&&(f.value.length||u.value.length)&&(h.value=E.setTimeout("task-poll",s,he()))))};e?s():h.value=E.setTimeout("task-poll",s,he())}async function Re(){if(O.value||!f.value.length&&!u.value.length){!f.value.length&&!u.value.length&&ue();return}O.value=!0;try{let e=!1,s=!1;const t=Array.from(new Set([...f.value,...u.value]));if(t.length){const n=await rs(t,{force:u.value.length>0});for(const l of n.items||[]){const o=l.task;if(!o?.id)continue;const d=l.items?.[0];if(d&&(w.value={...w.value,[o.id]:d},Ae(d)),(o.status==="SUCCESS"||o.status==="FAILED")&&(Y(o.id),e=!0,o.status==="SUCCESS"?Fe(o.id):Q(o.id)),d&&o.status==="SUCCESS"&&u.value.includes(o.id)){const y=(d.fileStatus||"").toUpperCase();(d.fileReady||y==="SUCCESS"||y==="FAILED")&&(Q(o.id),e=!0,s=!0)}}n.missingTaskIds?.length&&(n.missingTaskIds.forEach(l=>{Y(l),Q(l)}),s=!0,e=!0)}e&&await H(),s&&await L(),Ee()}finally{O.value=!1}}function Ae(e){if(!e.taskId&&!e.resultId)return;const s=g.value.findIndex(t=>e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId);s>=0?g.value[s]={...g.value[s],...e}:g.value=[e,...g.value]}function Ee(){if(!u.value.length)return;const e=[];for(const s of u.value){const t=g.value.find(o=>o.taskId===s);if(!t){e.push(s);continue}const n=(t.taskStatus||"").toUpperCase(),l=(t.fileStatus||"").toUpperCase();n==="FAILED"||t.fileReady||l==="SUCCESS"||l==="FAILED"||n==="SUCCESS"&&e.push(s)}u.value=e,S(),u.value.length&&m()}function xe(){const e=g.value.filter(s=>s.taskId!=null&&N(s)).map(s=>s.taskId);u.value=Array.from(new Set(e)),S(),u.value.length&&m()}function Ue(){const e=g.value.filter(s=>s.taskId!=null&&k(s)==="RUNNING").map(s=>s.taskId);e.length&&(f.value=Array.from(new Set([...f.value,...e])),S(),m())}async function H(){x.value=await Ze()}async function L(e={}){const s=Date.now();if(!(!e.force&&g.value.length&&s-ae{g.value=De(g.value,t.items||[]),ae=Date.now()}).finally(()=>{R=null}),R)}function De(e,s){const t=new Map,n=new Map;for(const l of e||[])l.taskId!=null&&t.set(l.taskId,l),l.resultId!=null&&n.set(l.resultId,l);return(s||[]).map(l=>{const o=l.resultId!=null?n.get(l.resultId):l.taskId!=null?t.get(l.taskId):void 0;return $e(o,l)})}function $e(e,s){return!e||!((k(e)==="RUNNING"||N(e)||U(e))&&!U(s)&&!ee(s))?s:{...s,fileJobId:s.fileJobId??e.fileJobId,fileStatus:s.fileStatus||e.fileStatus,fileError:s.fileError||e.fileError,fileReady:s.fileReady||e.fileReady,fileProgressPercent:X(s.fileProgressPercent)?s.fileProgressPercent:e.fileProgressPercent,fileProgressCurrent:X(s.fileProgressCurrent)?s.fileProgressCurrent:e.fileProgressCurrent,fileProgressTotal:X(s.fileProgressTotal)?s.fileProgressTotal:e.fileProgressTotal,fileProgressMessage:(s.fileProgressMessage||"").trim()?s.fileProgressMessage:e.fileProgressMessage}}function X(e){const s=Number(e);return Number.isFinite(s)&&s>0}function ie(e){const s=k(e);return s==="RUNNING"?"执行中":s==="PENDING"?"已解析待推送":N(e)?"结果生成中":Z(e)?"结果生成失败":s==="SUCCESS"||e.success?"已完成":s==="FAILED"?"失败":"等待中"}function Me(e){const s=k(e);return s==="RUNNING"||N(e)?"running":Z(e)||s==="FAILED"?"failed":s==="SUCCESS"||e.success?"success":"pending"}function N(e){const s=k(e),t=(e.fileStatus||"").toUpperCase();return!(s!=="SUCCESS"||ee(e)||t==="FAILED"||t==="SUCCESS")}function k(e){return(e.taskStatus||"").toUpperCase()}function Z(e){return(e.fileStatus||"").toUpperCase()==="FAILED"}function K(e){if(Z(e))return e.fileError||"结果文件生成失败,请稍后重试或检查后端日志";if(U(e)||!N(e))return"";const s=(e.fileStatus||"").toUpperCase();return s==="RUNNING"?"任务已完成,正在等待 Coze 回流并组装结果文件,下载按钮稍后出现":s==="PENDING"?"任务已完成,结果文件已入队,正在等待后端开始处理":"任务已完成,正在生成结果文件,下载按钮稍后出现"}function ee(e){return!!(e.resultId&&(e.fileReady||e.downloadUrl))}function J(e){const s=Number(e.fileProgressPercent||0);return Number.isFinite(s)&&s>0?Math.max(0,Math.min(100,Math.round(s))):pe(e)?fe(e)==="PENDING"?6:10:0}function ce(e,s){const t=(e.fileProgressMessage||"").trim();return t?ze(t):s}function ze(e){const s=e.match(/^Coze submitted (\d+) batches, completed (\d+), waiting for results$/);if(s)return`已提交 Coze ${s[1]} 批,已完成 ${s[2]} 批,等待结果回流`;const t=e.match(/^Coze completed (\d+) batches, waiting for remaining Python data$/);return t?`Coze 已完成 ${t[1]} 批,等待 Python 继续回传数据`:{"Receiving Python data, waiting for 50 rows before Coze":"正在接收 Python 数据,累计 50 条后提交 Coze","Submitting Coze":"正在提交 Coze","Coze submitted, waiting for result":"Coze 已提交,等待结果回流","Waiting for Python upload":"等待 Python 继续回传数据","Coze results ready, assembling xlsx":"Coze 结果已回流,正在组装 xlsx","Assembling xlsx":"正在组装 xlsx","Uploading result file":"正在上传结果文件","Result file generated":"结果文件已生成"}[e]||e}function U(e){return(k(e)==="RUNNING"||N(e))&&(de(e)||pe(e))}function de(e){return Ge(e)||Number(e.fileProgressPercent||0)>0||!!(e.fileProgressMessage||"").trim()}function Ge(e){return(e.fileProgressTotal||0)>0}function fe(e){return(e.fileStatus||"").toUpperCase()}function Be(e){const s=fe(e);return e.fileJobId!=null||s==="PENDING"||s==="RUNNING"}function pe(e){return Be(e)&&!de(e)}async function He(e){if(!e.resultId)return;const s=e.downloadUrl||ss(e.resultId),t=e.resultFilename||`${e.sourceFilename||"appearance-patent"}.xlsx`,n=await ts(s,t,`appearance-patent:${e.resultId}`);n.success?p.success(`已保存: ${n.path||t}`):n.error&&n.error!=="用户取消"&&p.error(n.error)}async function ve(e){try{e.taskStatus==="RUNNING"&&e.taskId?(await as(e.taskId),Y(e.taskId)):e.resultId&&await ns(e.resultId),await H(),await L({force:!0}),p.success("已删除")}catch(s){p.error(s instanceof Error?s.message:"删除失败")}}return Ke(async()=>{Pe(),await Promise.all([H().catch(()=>{}),L().catch(()=>{})]),Ue(),xe(),(f.value.length||u.value.length)&&m()}),Je(()=>{A=!0,ue(),E.clearScope()}),(e,s)=>(i(),c("div",fs,[qe(je,{active:"appearance-patent"}),a("div",ps,[a("aside",vs,[s[3]||(s[3]=a("div",{class:"section-title"},"上传文件",-1)),a("div",gs,[s[1]||(s[1]=a("div",{class:"hint"},"选择 Excel 后点击解析,后端会提取 id、ASIN、国家,并保留整数 id 与子数据的第一条。",-1)),a("div",{class:"btns"},[a("button",{type:"button",class:"opt-btn",onClick:we},"选择 Excel"),a("button",{type:"button",class:"opt-btn",onClick:Ce},"选择文件夹")]),a("div",hs,[D.value.length?(i(!0),c(se,{key:1},te(D.value,t=>(i(),c("span",{key:t},r(t),1))),128)):(i(),c("span",ys,"暂未选择文件"))])]),a("div",ks,[s[2]||(s[2]=a("div",{class:"section-title"},"新增条件要求",-1)),Oe(a("textarea",{"onUpdate:modelValue":s[0]||(s[0]=t=>$.value=t),class:"prompt-input",rows:"8",placeholder:"可选,留空则不向 Coze 传 prompt 字段;填写后将作为 prompt 透传"},null,512),[[Ve,$.value]])]),a("div",Is,[a("button",{type:"button",class:"btn-run",disabled:M.value||!F.value.length,onClick:Se},r(M.value?"解析中...":"解析并创建任务"),9,_s),a("button",{type:"button",class:"btn-run btn-queue",disabled:z.value||!P.value?.taskId,onClick:be},r(z.value?"推送中...":"推送到 Python 队列"),9,Ps)]),s[4]||(s[4]=a("p",{class:"loading-msg"},"Python 回传字段按 asin、国家、url、标题提交;后端接收分片后累计 50 条调用 Coze,当前任务区展示 Coze 回流和结果组装进度。",-1)),b.value?(i(),c("div",ws,[a("div",null,"任务 ID:"+r(b.value.taskId),1),a("div",null,"总行数:"+r(b.value.totalRows)+",有效:"+r(b.value.acceptedRows)+",分组:"+r(b.value.groupCount||0)+",过滤:"+r(b.value.droppedRows),1)])):_("",!0),C.value?(i(),c("pre",Cs,r(C.value),1)):_("",!0)]),a("section",Ss,[s[12]||(s[12]=a("div",{class:"panel-header"},"外观专利检测",-1)),a("div",bs,[a("div",ms,[a("div",Ns,[s[5]||(s[5]=a("span",{class:"summary-label"},"运行中任务",-1)),a("strong",null,r(x.value.pendingTaskCount),1)]),a("div",Fs,[s[6]||(s[6]=a("span",{class:"summary-label"},"已结束任务",-1)),a("strong",null,r(x.value.processedTaskCount),1)]),a("div",Ts,[s[7]||(s[7]=a("span",{class:"summary-label"},"成功任务",-1)),a("strong",null,r(x.value.successTaskCount),1)]),a("div",Rs,[s[8]||(s[8]=a("span",{class:"summary-label"},"失败任务",-1)),a("strong",null,r(x.value.failedTaskCount),1)])]),s[11]||(s[11]=a("div",{class:"subsection-title"},"匹配任务",-1)),a("div",As,[s[9]||(s[9]=a("div",{class:"result-list-header"},[a("span",null,"当前任务")],-1)),ne.value.length?(i(),c("ul",xs,[(i(!0),c(se,null,te(ne.value,t=>(i(),c("li",{key:`cur-${t.taskId}`,class:"task-item"},[a("div",Us,[a("span",Ds,r(t.sourceFilename||"外观专利检测"),1),a("div",$s,"任务 ID:"+r(t.taskId),1),a("div",Ms,"开始时间:"+r(B(t.startedAt||t.createdAt)),1),a("div",zs,"结束时间:"+r(B(t.finishedAt)),1),a("div",Gs,"行数:"+r(t.rowCount??"-"),1),K(t)?(i(),c("div",Bs,r(K(t)),1)):_("",!0),U(t)?(i(),c("div",Hs,[a("div",Ls,[a("span",null,r(ce(t,"处理中")),1),a("span",null,r(J(t))+"%",1)]),a("div",Ks,[a("div",{class:"file-progress-bar",style:ge({width:`${J(t)}%`})},null,4)])])):_("",!0)]),a("div",Js,[a("span",qs,r(ie(t)),1),a("button",{type:"button",class:"btn-delete",onClick:n=>ve(t)},"删除",8,js)])]))),128))])):(i(),c("div",Es,"暂无当前任务"))]),a("div",Os,[s[10]||(s[10]=a("div",{class:"result-list-header"},[a("span",null,"历史记录")],-1)),le.value.length?(i(),c("ul",Ws,[(i(!0),c(se,null,te(le.value,t=>(i(),c("li",{key:`his-${t.resultId}-${t.taskId}`,class:"task-item"},[a("div",Ys,[a("span",Qs,r(t.sourceFilename||"外观专利检测"),1),a("div",Xs,"任务 ID:"+r(t.taskId??"-"),1),a("div",Zs,"开始时间:"+r(B(t.startedAt||t.createdAt)),1),a("div",et,"结束时间:"+r(B(t.finishedAt)),1),t.resultFilename?(i(),c("div",st,r(t.resultFilename||"下载结果"),1)):_("",!0),K(t)?(i(),c("div",tt,r(K(t)),1)):_("",!0),U(t)?(i(),c("div",at,[a("div",nt,[a("span",null,r(ce(t,"结果生成中")),1),a("span",null,r(J(t))+"%",1)]),a("div",lt,[a("div",{class:"file-progress-bar",style:ge({width:`${J(t)}%`})},null,4)])])):_("",!0),t.error?(i(),c("div",rt,"错误:"+r(t.error),1)):_("",!0)]),a("div",ot,[a("span",{class:We(["status",Me(t)])},r(ie(t)),3),ee(t)?(i(),c("button",{key:0,type:"button",class:"download",onClick:n=>He(t)},"下载",8,ut)):_("",!0),t.resultId?(i(),c("button",{key:1,type:"button",class:"btn-delete",onClick:n=>ve(t)},"删除",8,it)):_("",!0)])]))),128))])):(i(),c("div",Vs,"暂无历史记录"))])])])])]))}}),ft=os(dt,[["__scopeId","data-v-7a18cb78"]]);us(ft).use(is).mount("#app"); diff --git a/app/assets/brand-jr47vQUd.js b/app/assets/brand-COze15GJ.js similarity index 57% rename from app/assets/brand-jr47vQUd.js rename to app/assets/brand-COze15GJ.js index 0b82dda..1b50ada 100644 --- a/app/assets/brand-jr47vQUd.js +++ b/app/assets/brand-COze15GJ.js @@ -1 +1 @@ -import{bN as r}from"./java-modules-DzYrjxib.js";const n="";function s(e){return r(`${n}/api/brand/expand-folder-recursive`,{folder:e})}export{s as e}; +import{bN as r}from"./java-modules-B8c-YG5x.js";const n="";function s(e){return r(`${n}/api/brand/expand-folder-recursive`,{folder:e})}export{s as e}; diff --git a/app/assets/collect-data-6h7Mh27f.css b/app/assets/collect-data-6h7Mh27f.css deleted file mode 100644 index 63adff0..0000000 --- a/app/assets/collect-data-6h7Mh27f.css +++ /dev/null @@ -1 +0,0 @@ -.module-page[data-v-14b8e8a2]{min-height:100vh;background:#1a1a1a}.main-content[data-v-14b8e8a2]{display:flex;height:calc(100vh - 56px);min-height:calc(100vh - 56px)}.left-panel[data-v-14b8e8a2]{width:400px;background:#1e1e1e;padding:20px;overflow-y:auto;border-right:1px solid #2a2a2a}.right-panel[data-v-14b8e8a2]{flex:1;min-width:0;background:#1a1a1a;display:flex;flex-direction:column}.section-title[data-v-14b8e8a2],.subsection-title[data-v-14b8e8a2]{font-size:13px;color:#bbb;margin:12px 0 10px}.upload-zone[data-v-14b8e8a2]{border:1px dashed #3a3a3a;border-radius:10px;padding:18px;background:#252525;margin-bottom:18px}.hint[data-v-14b8e8a2],.loading-msg[data-v-14b8e8a2],.files[data-v-14b8e8a2],.muted[data-v-14b8e8a2]{color:#888;font-size:12px;line-height:1.5}.btns[data-v-14b8e8a2],.run-row[data-v-14b8e8a2]{display:flex;gap:10px;flex-wrap:wrap}.opt-btn[data-v-14b8e8a2],.btn-run[data-v-14b8e8a2],.btn-delete[data-v-14b8e8a2],.download[data-v-14b8e8a2]{border:none;cursor:pointer;border-radius:7px}.opt-btn[data-v-14b8e8a2]{padding:8px 14px;color:#ccc;background:#2a2a2a;border:1px solid #3a3a3a}.btn-run[data-v-14b8e8a2]{padding:10px 18px;color:#fff;background:#3498db;font-weight:600}.btn-run.btn-queue[data-v-14b8e8a2]{background:#27ae60}.btn-run[data-v-14b8e8a2]:disabled{opacity:.55;cursor:not-allowed}.selected-files[data-v-14b8e8a2]{margin-top:14px;color:#999;font-size:12px;word-break:break-all}.selected-files span[data-v-14b8e8a2]{display:block;margin:4px 0}.selected-files .more-line[data-v-14b8e8a2]{color:#777}.filter-zone[data-v-14b8e8a2]{border:1px solid #2a2a2a;border-radius:8px;padding:12px;background:#252525;margin-bottom:14px;display:flex;flex-direction:column;gap:10px}.filter-row[data-v-14b8e8a2]{display:flex;align-items:center;gap:10px}.filter-label[data-v-14b8e8a2]{width:110px;color:#bbb;font-size:12px}.filter-input[data-v-14b8e8a2]{flex:1;padding:6px 10px;background:#1e1e1e;border:1px solid #3a3a3a;border-radius:6px;color:#ddd;font-size:13px;outline:none}.filter-input[data-v-14b8e8a2]:focus{border-color:#3498db}.filter-checks[data-v-14b8e8a2]{display:flex;gap:16px}.filter-check-row[data-v-14b8e8a2]{display:inline-flex;align-items:center;gap:6px;cursor:pointer;-webkit-user-select:none;user-select:none;color:#ccc;font-size:12px}.filter-check-input[data-v-14b8e8a2]{width:16px;height:16px;accent-color:#409eff;cursor:pointer}.country-pref-hint[data-v-14b8e8a2]{margin-top:-4px}.country-section-title[data-v-14b8e8a2]{display:flex;align-items:center;justify-content:space-between;gap:12px}.country-pref-saving[data-v-14b8e8a2]{color:#3498db;font-size:11px}.country-pref-checks[data-v-14b8e8a2]{display:flex;flex-wrap:wrap;gap:10px 16px;margin-bottom:12px}.country-check-row[data-v-14b8e8a2]{display:inline-flex;align-items:center;gap:8px;cursor:pointer;-webkit-user-select:none;user-select:none;font-size:12px;color:#ccc}.country-check-input[data-v-14b8e8a2]{width:16px;height:16px;accent-color:#409eff;cursor:pointer;flex-shrink:0}.country-check-text[data-v-14b8e8a2]{line-height:1.3}.country-order-panel[data-v-14b8e8a2]{border:1px solid #333;border-radius:8px;padding:10px 12px;background:#252525;margin-bottom:14px}.country-order-caption[data-v-14b8e8a2]{font-size:11px;color:#777;margin-bottom:8px}.country-order-list[data-v-14b8e8a2]{display:flex;flex-direction:column;gap:6px}.country-drag-row[data-v-14b8e8a2]{display:flex;align-items:center;gap:10px;padding:8px 10px;background:#2c2c2c;border-radius:6px;border:1px solid #3a3a3a;cursor:grab;-webkit-user-select:none;user-select:none}.country-drag-row.dragging[data-v-14b8e8a2]{opacity:.55;border-color:#3498db}.drag-handle[data-v-14b8e8a2]{color:#666;font-size:12px;letter-spacing:-2px}.country-drag-label[data-v-14b8e8a2]{font-size:12px;color:#ccc}.queue-debug-card[data-v-14b8e8a2]{margin-top:14px;border:1px solid #2a2a2a;border-radius:8px;padding:10px 12px;background:#1f1f1f}.queue-debug-title[data-v-14b8e8a2]{margin-top:0}.queue-debug-line[data-v-14b8e8a2]{color:#9ad;font-size:12px}.queue-debug-payload[data-v-14b8e8a2]{margin-top:8px;padding:8px 10px;background:#181818;border-radius:6px;color:#bbb;font-size:11px;overflow:auto;max-height:200px}.panel-header[data-v-14b8e8a2]{padding:16px 20px;border-bottom:1px solid #2a2a2a;font-size:15px;font-weight:600;color:#ddd}.task-list-wrap[data-v-14b8e8a2]{flex:1;padding:16px 20px;overflow:auto}.clean-result-summary[data-v-14b8e8a2]{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin-bottom:16px}.summary-card[data-v-14b8e8a2]{padding:14px 16px;border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e}.summary-card strong[data-v-14b8e8a2]{display:block;margin-top:8px;color:#eaf4ff;font-size:22px}.summary-label[data-v-14b8e8a2]{color:#8d8d8d;font-size:12px}.result-list-wrap[data-v-14b8e8a2]{border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e;min-height:180px;margin:0 0 16px}.result-list-header[data-v-14b8e8a2]{display:flex;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #2a2a2a;color:#ddd;font-size:14px}.empty-tasks[data-v-14b8e8a2]{color:#666;font-size:13px;padding:18px;text-align:center}.task-list[data-v-14b8e8a2]{list-style:none;margin:0;padding:12px}.task-item[data-v-14b8e8a2]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:12px 14px;border:1px solid #2a2a2a;border-radius:8px;margin-bottom:8px;background:#222}.left[data-v-14b8e8a2]{flex:1;min-width:0}.id[data-v-14b8e8a2]{color:#e0e0e0;font-size:13px;font-weight:600}.task-right[data-v-14b8e8a2]{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.status[data-v-14b8e8a2]{padding:4px 10px;border-radius:6px;font-size:12px}.status.success[data-v-14b8e8a2]{background:#2ecc712e;color:#2ecc71}.status.failed[data-v-14b8e8a2]{background:#e74c3c2e;color:#ff6b6b}.status.running[data-v-14b8e8a2]{background:#3498db2e;color:#3498db}.status.pending[data-v-14b8e8a2]{background:#95a5a62e;color:#bdc3c7}.btn-delete[data-v-14b8e8a2]{padding:6px 10px;color:#ff8f8f;background:#e74c3c1f}@media(max-width:1100px){.main-content[data-v-14b8e8a2]{flex-direction:column;height:auto}.left-panel[data-v-14b8e8a2]{width:100%;border-right:none;border-bottom:1px solid #2a2a2a}.clean-result-summary[data-v-14b8e8a2]{grid-template-columns:repeat(2,minmax(0,1fr))}} diff --git a/app/assets/collect-data-DPGAQszU.css b/app/assets/collect-data-DPGAQszU.css new file mode 100644 index 0000000..4a15f4c --- /dev/null +++ b/app/assets/collect-data-DPGAQszU.css @@ -0,0 +1 @@ +.module-page[data-v-421c638b]{min-height:100vh;background:#1a1a1a}.main-content[data-v-421c638b]{display:flex;height:calc(100vh - 56px);min-height:calc(100vh - 56px)}.left-panel[data-v-421c638b]{width:400px;background:#1e1e1e;padding:20px;overflow-y:auto;border-right:1px solid #2a2a2a}.right-panel[data-v-421c638b]{flex:1;min-width:0;background:#1a1a1a;display:flex;flex-direction:column}.section-title[data-v-421c638b],.subsection-title[data-v-421c638b]{font-size:13px;color:#bbb;margin:12px 0 10px}.upload-zone[data-v-421c638b]{border:1px dashed #3a3a3a;border-radius:10px;padding:18px;background:#252525;margin-bottom:18px}.hint[data-v-421c638b],.loading-msg[data-v-421c638b],.files[data-v-421c638b],.muted[data-v-421c638b]{color:#888;font-size:12px;line-height:1.5}.btns[data-v-421c638b],.run-row[data-v-421c638b]{display:flex;gap:10px;flex-wrap:wrap}.opt-btn[data-v-421c638b],.btn-run[data-v-421c638b],.btn-delete[data-v-421c638b],.download[data-v-421c638b]{border:none;cursor:pointer;border-radius:7px}.opt-btn[data-v-421c638b]{padding:8px 14px;color:#ccc;background:#2a2a2a;border:1px solid #3a3a3a}.btn-run[data-v-421c638b]{padding:10px 18px;color:#fff;background:#3498db;font-weight:600}.btn-run.btn-queue[data-v-421c638b]{background:#27ae60}.btn-run[data-v-421c638b]:disabled{opacity:.55;cursor:not-allowed}.selected-files[data-v-421c638b]{margin-top:14px;color:#999;font-size:12px;word-break:break-all}.selected-files span[data-v-421c638b]{display:block;margin:4px 0}.selected-files .more-line[data-v-421c638b]{color:#777}.filter-zone[data-v-421c638b]{border:1px solid #2a2a2a;border-radius:8px;padding:12px;background:#252525;margin-bottom:14px;display:flex;flex-direction:column;gap:10px}.filter-row[data-v-421c638b]{display:flex;align-items:center;gap:10px}.filter-label[data-v-421c638b]{width:110px;color:#bbb;font-size:12px}.filter-input[data-v-421c638b]{flex:1;min-width:0;padding:6px 10px;background:#1e1e1e;border:1px solid #3a3a3a;border-radius:6px;color:#ddd;font-size:13px;outline:none}.filter-input[data-v-421c638b]:focus{border-color:#3498db}.range-inputs[data-v-421c638b]{flex:1;min-width:0;display:flex;align-items:center;gap:8px}.range-separator[data-v-421c638b]{color:#777;font-size:12px;white-space:nowrap}.filter-checks[data-v-421c638b]{display:flex;gap:16px}.filter-check-row[data-v-421c638b]{display:inline-flex;align-items:center;gap:6px;cursor:pointer;-webkit-user-select:none;user-select:none;color:#ccc;font-size:12px}.filter-check-input[data-v-421c638b]{width:16px;height:16px;accent-color:#409eff;cursor:pointer}.country-pref-hint[data-v-421c638b]{margin-top:-4px}.country-section-title[data-v-421c638b]{display:flex;align-items:center;justify-content:space-between;gap:12px}.country-pref-saving[data-v-421c638b]{color:#3498db;font-size:11px}.country-pref-radios[data-v-421c638b]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-bottom:14px}.country-check-row[data-v-421c638b]{display:inline-flex;align-items:center;gap:8px;cursor:pointer;-webkit-user-select:none;user-select:none;font-size:12px;color:#ccc;padding:8px 10px;border:1px solid #333;border-radius:8px;background:#252525}.country-check-row.selected[data-v-421c638b]{border-color:#409eff;background:#409eff1f;color:#e6f2ff}.country-check-input[data-v-421c638b]{width:16px;height:16px;accent-color:#409eff;cursor:pointer;flex-shrink:0}.country-check-text[data-v-421c638b]{line-height:1.3}.queue-debug-card[data-v-421c638b]{margin-top:14px;border:1px solid #2a2a2a;border-radius:8px;padding:10px 12px;background:#1f1f1f}.queue-debug-title[data-v-421c638b]{margin-top:0}.queue-debug-line[data-v-421c638b]{color:#9ad;font-size:12px}.queue-debug-payload[data-v-421c638b]{margin-top:8px;padding:8px 10px;background:#181818;border-radius:6px;color:#bbb;font-size:11px;overflow:auto;max-height:200px}.panel-header[data-v-421c638b]{padding:16px 20px;border-bottom:1px solid #2a2a2a;font-size:15px;font-weight:600;color:#ddd}.task-list-wrap[data-v-421c638b]{flex:1;padding:16px 20px;overflow:auto}.clean-result-summary[data-v-421c638b]{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin-bottom:16px}.summary-card[data-v-421c638b]{padding:14px 16px;border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e}.summary-card strong[data-v-421c638b]{display:block;margin-top:8px;color:#eaf4ff;font-size:22px}.summary-label[data-v-421c638b]{color:#8d8d8d;font-size:12px}.result-list-wrap[data-v-421c638b]{border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e;min-height:180px;margin:0 0 16px}.result-list-header[data-v-421c638b]{display:flex;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #2a2a2a;color:#ddd;font-size:14px}.empty-tasks[data-v-421c638b]{color:#666;font-size:13px;padding:18px;text-align:center}.task-list[data-v-421c638b]{list-style:none;margin:0;padding:12px}.task-item[data-v-421c638b]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:12px 14px;border:1px solid #2a2a2a;border-radius:8px;margin-bottom:8px;background:#222}.left[data-v-421c638b]{flex:1;min-width:0}.id[data-v-421c638b]{color:#e0e0e0;font-size:13px;font-weight:600}.task-right[data-v-421c638b]{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.status[data-v-421c638b]{padding:4px 10px;border-radius:6px;font-size:12px}.status.success[data-v-421c638b]{background:#2ecc712e;color:#2ecc71}.status.failed[data-v-421c638b]{background:#e74c3c2e;color:#ff6b6b}.status.running[data-v-421c638b]{background:#3498db2e;color:#3498db}.status.pending[data-v-421c638b]{background:#95a5a62e;color:#bdc3c7}.btn-delete[data-v-421c638b]{padding:6px 10px;color:#ff8f8f;background:#e74c3c1f}@media(max-width:1100px){.main-content[data-v-421c638b]{flex-direction:column;height:auto}.left-panel[data-v-421c638b]{width:100%;border-right:none;border-bottom:1px solid #2a2a2a}.clean-result-summary[data-v-421c638b]{grid-template-columns:repeat(2,minmax(0,1fr))}} diff --git a/app/assets/collect-data.js b/app/assets/collect-data.js index ed51b46..39da0e7 100644 --- a/app/assets/collect-data.js +++ b/app/assets/collect-data.js @@ -1 +1 @@ -import{g,bB as _e,bC as ce,V as we,d as Ce,o as Se,a as c,c as d,b as Ie,B as Te,e as a,F as G,r as O,t as i,f as F,w as Y,H as ne,v as le,y as re,ai as oe,n as ie,bD as Ne,h as ue,E as h,bE as Pe,bF as Ee,i as Q,bG as De,bH as xe,bI as Fe,bJ as Ae,bK as Ue,bL as $e,bM as Le,_ as Re,q as Be,u as Me}from"./java-modules-DzYrjxib.js";import{e as qe}from"./brand-jr47vQUd.js";import{c as de}from"./categorized-timers-JPA-olTr.js";const Ge=v=>v==="SUCCESS"||v==="FAILED";function Ke(v){if(!v||typeof window>"u")return[];try{const m=window.localStorage.getItem(v);if(!m)return[];const _=JSON.parse(m);return Array.isArray(_)?_.filter(S=>typeof S=="number"&&S>0):[]}catch{return[]}}function Ve(v,m){if(!(!v||typeof window>"u"))try{m.length===0?window.localStorage.removeItem(v):window.localStorage.setItem(v,JSON.stringify(m))}catch{}}function Oe(v){const m=de(`task-progress-loop:${v.scope}`),_=v.isTerminal??Ge,S=v.getIntervalMs??we,p=g(Ke(v.storageKey)),w=g({}),f=g(!1);let l=null,b=!1;function A(){Ve(v.storageKey,p.value)}function K(n){!Number.isFinite(n)||n<=0||p.value.includes(n)||(p.value=[...p.value,n],A(),x(!0))}function U(n){if(p.value.includes(n)&&(p.value=p.value.filter(o=>o!==n),A(),w.value[n])){const o={...w.value};delete o[n],w.value=o}}function N(n){const o=Array.from(new Set(n.filter(L=>Number.isFinite(L)&&L>0)));p.value=o,A()}function I(n){const o=w.value[n];return!!o&&_(o)}async function P(){if(b)return;const n=p.value.filter(o=>o>0);if(n.length){f.value=!0;try{const L=(await v.fetchProgress(n))?.items||[],z=[],H={...w.value};for(const C of L){const R=v.extractTaskId(C);if(typeof R!="number"||R<=0)continue;const q=v.extractStatus(C)||"";try{v.onUpdate?.(R,C)}catch{}q&&(H[R]=q,_(q)&&z.push({taskId:R,detail:C,status:q}))}w.value=H;for(const C of z){U(C.taskId);try{await v.onTerminal?.(C.taskId,C.detail,C.status)}catch{}}}catch(o){v.onError?.(o)}finally{f.value=!1}}}function M(){l!=null&&(m.clearTimer("task-poll",l),l=null)}function D(n=!1){if(b||l!=null&&!n)return;M();const o=async()=>{if(l=null,!b&&p.value.length){if(f.value){l=m.setTimeout("task-poll",o,500);return}await P(),!b&&p.value.length>0&&(l=m.setTimeout("task-poll",o,S()))}};n?o():l=m.setTimeout("task-poll",o,S())}function x(n=!1){b||p.value.length&&(l!=null&&!n||D(n))}function $(){M()}_e(p,(n,o)=>{if(!b){if(!n.length){$();return}(!o||o.length===0)&&D(!0)}},{flush:"post"});let E=null;typeof document<"u"&&(E=()=>{document.visibilityState==="visible"&&p.value.length>0&&D(!0)},document.addEventListener("visibilitychange",E));function T(){b||(b=!0,$(),m.clearScope(),E&&typeof document<"u"&&(document.removeEventListener("visibilitychange",E),E=null))}return ce(()=>T()),p.value.length>0&&D(!0),{taskIds:p,taskStatuses:w,inFlight:f,add:K,remove:U,reset:N,ensure:x,stop:$,refreshOnce:P,isTerminal:I,dispose:T}}const ze={class:"page-shell module-page"},He={class:"main-content"},Je={class:"left-panel"},je={class:"upload-zone"},Ye={class:"selected-files"},Qe={key:0,class:"more-line"},We={key:1},Xe={class:"filter-zone"},Ze={class:"filter-row"},et={class:"filter-row"},tt={class:"filter-checks"},st={class:"filter-check-row"},at={class:"filter-check-row"},nt={class:"section-title country-section-title"},lt={key:0,class:"country-pref-saving"},rt={class:"country-pref-checks"},ot=["checked","disabled","onChange"],it={class:"country-check-text"},ut={key:0,class:"country-order-panel"},ct={class:"country-order-list"},dt=["onDragstart","onDrop"],ft={class:"country-drag-label"},vt={class:"run-row"},pt=["disabled"],yt=["disabled"],ht={key:1,class:"queue-debug-card"},gt={class:"queue-debug-line"},kt={key:0,class:"queue-debug-payload"},mt={class:"right-panel"},bt={class:"task-list-wrap"},_t={class:"clean-result-summary"},wt={class:"summary-card"},Ct={class:"summary-card"},St={class:"summary-card"},It={class:"summary-card"},Tt={class:"result-list-wrap"},Nt={key:0,class:"empty-tasks"},Pt={key:1,class:"task-list clean-result-list"},Et={class:"left"},Dt={class:"id"},xt={class:"files"},Ft={class:"files"},At={class:"files"},Ut={class:"task-right"},$t={class:"status running"},Lt=["onClick"],Rt={class:"result-list-wrap"},Bt={key:0,class:"empty-tasks"},Mt={key:1,class:"task-list clean-result-list"},qt={class:"left"},Gt={class:"id"},Kt={class:"files"},Vt={class:"files"},Ot={class:"files"},zt={key:0,class:"files"},Ht={key:1,class:"files"},Jt={class:"task-right"},jt=["onClick"],Yt="brand:collect-data:polling-task-ids",Qt=Ce({__name:"BrandCollectDataTab",setup(v){const m=[{code:"DE",label:"德国"},{code:"UK",label:"英国"},{code:"FR",label:"法国"},{code:"IT",label:"意大利"},{code:"ES",label:"西班牙"}],_=g([]),S=g([]),p=g(!1),w=g(!1),f=Ne({amount:null,rank:null,fba:!1,fbm:!1}),l=g(["DE","UK","FR","IT","ES"]),b=g(null),A=g(!1),K=g(!1),U=de("collect-data-tab");let N=null;const I=g(null),P=g(null),M=g(""),D=g(""),x=g({pendingTaskCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),$=g([]),E=g([]),T=g({}),n=Oe({scope:"collect-data-tab",storageKey:Yt,fetchProgress:s=>Le(s),extractTaskId:s=>s.task?.id??null,extractStatus:s=>s.task?.status??"",onUpdate:(s,e)=>{const t=T.value[s];T.value={...T.value,[s]:t?{...t,task:{...t.task||{},...e.task||{}},items:e.items??t.items}:e}},onTerminal:async s=>{if(T.value[s]){const e={...T.value};delete e[s],T.value=e}await Promise.all([V(),J()])}}),o=ue(()=>_.value.slice(0,8));function L(s){return m.find(t=>t.code===s)?.label??s}const z=ue(()=>{const s=l.value,e=new Set(s),t=s.map(y=>({code:y,label:L(y)})),r=m.filter(y=>!e.has(y.code)).map(y=>({code:y.code,label:y.label}));return[...t,...r]});function H(s){return l.value.includes(s)}function C(s){return l.value.length===1&&l.value[0]===s}function R(s,e){const t=e.target;if(t){if(!t.checked&&C(s)){t.checked=!0,h.warning("至少保留 1 个国家");return}if(A.value=!0,t.checked)l.value.includes(s)||(l.value=[...l.value,s]);else{if(l.value.length<=1){h.warning("至少保留 1 个国家");return}l.value=l.value.filter(r=>r!==s)}X()}}function q(s){b.value=s}function fe(){b.value=null}function ve(s){const e=b.value;if(b.value=null,e==null||e===s)return;A.value=!0;const t=[...l.value],[r]=t.splice(e,1);t.splice(s,0,r),l.value=t,X()}function X(){N!=null&&U.clearTimer("country-pref-save",N),N=U.setTimeout("country-pref-save",()=>{N=null,pe()},450)}async function pe(){if(l.value.length){K.value=!0;try{await Pe([...l.value])}catch(s){h.error(s instanceof Error?s.message:"保存国家顺序失败")}finally{K.value=!1}}}async function ye(){try{const s=await Ee();if(A.value)return;const e=s?.country_codes;Array.isArray(e)&&e.length&&(l.value=[...e])}catch{}}async function Z(s){const e=Q();if(!e?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传能力");const t=[];for(const r of s){const y=typeof r=="string"?r:r.absolutePath,B=typeof r=="string"?void 0:r.relativePath,u=await e.upload_file_to_java(y,B);if(!u?.success||!u.data)throw new Error(u?.error||u?.message||`上传失败:${y}`);t.push(u.data)}return t}async function he(){const s=Q();if(!s?.select_brand_xlsx_files||!s.upload_file_to_java){h.warning("当前环境不支持文件选择或上传");return}try{const e=await s.select_brand_xlsx_files();if(!e?.length)return;const t=await Z(e);S.value=t,_.value=t.map(r=>r.relativePath||r.originalFilename||r.fileKey),I.value=null,P.value=null}catch(e){h.error(e instanceof Error?e.message:"文件选择失败")}}async function ge(){const s=Q();if(!s?.select_brand_folder){h.warning("当前环境不支持文件夹选择,请在本地客户端中打开");return}try{const e=await s.select_brand_folder();if(!e)return;const t=await qe(e);if(!t.success||!t.items?.length){h.warning(t.error||"该文件夹下没有可用的 xlsx 文件");return}const r=await Z(t.items);S.value=r,_.value=t.items.map(y=>y.relativePath||y.absolutePath),I.value=null,P.value=null,h.success(`已选择文件夹内 ${t.items.length} 个 Excel 文件`)}catch(e){h.error(e instanceof Error?e.message:"选择失败")}}function ee(){return{amount:f.amount===null||f.amount===void 0||Number.isNaN(f.amount)?null:f.amount,rank:f.rank===null||f.rank===void 0||Number.isNaN(f.rank)?null:f.rank,fba:!!f.fba,fbm:!!f.fbm,countryCodes:[...l.value]}}async function ke(){if(!S.value.length){h.warning("请先选择 Excel 文件");return}if(!l.value.length){h.warning("至少保留 1 个国家");return}p.value=!0;try{const s=await De({files:S.value.map(e=>({fileKey:e.fileKey,originalFilename:e.originalFilename,relativePath:e.relativePath})),task_type:"collect-data",filters:ee()});P.value=s,I.value=s.taskId??null,s.taskId&&n.add(s.taskId),h.success(`提交成功:任务 ${s.taskNo||s.taskId},落库 ${s.acceptedRows??0} 行`),await Promise.all([V(),J()])}catch(s){h.error(s instanceof Error?s.message:"提交失败")}finally{p.value=!1}}async function me(){if(!I.value){h.warning("请先提交采集任务");return}const s=Q();if(!s?.enqueue_json){h.warning("当前环境未提供 Python 队列能力");return}w.value=!0;try{await xe(I.value);const e={type:"collect-data-run",ts:Date.now(),data:{taskId:I.value,taskNo:P.value?.taskNo,taskType:"collect-data",totalRows:P.value?.acceptedRows??0,pageSize:P.value?.pageSize??50,filters:ee()}},t=await s.enqueue_json(e);if(!t?.success)throw new Error(t?.error||"入队失败");M.value=`已推送至 Python 队列(队列长度:${t.queue_size??"-"})`,D.value=JSON.stringify(e,null,2),I.value&&n.add(I.value),h.success("已推送到 Python 队列"),await V()}catch(e){h.error(e instanceof Error?e.message:"推送失败")}finally{w.value=!1}}function W(s){if(!s)return"-";const e=new Date(s);if(Number.isNaN(e.getTime()))return s;const t=e.getFullYear(),r=String(e.getMonth()+1).padStart(2,"0"),y=String(e.getDate()).padStart(2,"0"),B=String(e.getHours()).padStart(2,"0"),u=String(e.getMinutes()).padStart(2,"0"),k=String(e.getSeconds()).padStart(2,"0");return`${t}-${r}-${y} ${B}:${u}:${k}`}function te(s){return(s.taskStatus||"").toUpperCase()}function se(s){const e=te(s);return e==="RUNNING"?"执行中":e==="PENDING"?"等待中":e==="SUCCESS"||s.success?"已完成":e==="FAILED"?"失败":"等待中"}function be(s){const e=te(s);return e==="RUNNING"?"running":e==="FAILED"?"failed":e==="SUCCESS"||s.success?"success":"pending"}async function V(){try{x.value=await Fe()}catch{}}async function J(){try{const e=(await Ae(50)).items||[],t=e.filter(u=>{const k=(u.taskStatus||"").toUpperCase();return k==="PENDING"||k==="RUNNING"});E.value=e.filter(u=>{const k=(u.taskStatus||"").toUpperCase();return k==="SUCCESS"||k==="FAILED"});const r=new Set;for(const u of t)u.taskId&&(r.add(u.taskId),n.add(u.taskId));for(const u of[...n.taskIds.value])e.some(j=>j.taskId===u)||n.remove(u);const y=new Set(t.map(u=>u.taskId).filter(u=>typeof u=="number")),B=[...t];for(const u of n.taskIds.value){if(y.has(u))continue;const k=T.value[u],j=k?.items?.[0];j?B.push(j):k?.task&&B.push({taskId:k.task.id,taskNo:k.task.taskNo,taskStatus:k.task.status,startedAt:k.task.createdAt,finishedAt:k.task.finishedAt,sourceFilename:"采集数据"})}$.value=B}catch{}}async function ae(s){try{if(s.resultId)await Ue(s.resultId);else if(s.taskId)await $e(s.taskId);else return;s.taskId&&n.remove(s.taskId),h.success("已删除"),await Promise.all([V(),J()])}catch(e){h.error(e instanceof Error?e.message:"删除失败")}}return Se(()=>{ye(),V(),J()}),ce(()=>{N!=null&&(U.clearTimer("country-pref-save",N),N=null),U.clearScope()}),(s,e)=>(c(),d("div",ze,[Ie(Te,{active:"collect-data"}),a("div",He,[a("aside",Je,[e[14]||(e[14]=a("div",{class:"section-title"},"上传文件",-1)),a("div",je,[e[5]||(e[5]=a("div",{class:"hint"},"选择需要采集的 Excel 文件或文件夹(默认根目录:采集前数据.xlsx),后续将按下方筛选条件交给 Python 端进行数据采集。",-1)),a("div",{class:"btns"},[a("button",{type:"button",class:"opt-btn",onClick:he},"选择 Excel"),a("button",{type:"button",class:"opt-btn",onClick:ge},"选择文件夹")]),a("div",Ye,[_.value.length?(c(),d(G,{key:0},[(c(!0),d(G,null,O(o.value,t=>(c(),d("span",{key:t},i(t),1))),128)),_.value.length>o.value.length?(c(),d("span",Qe," 还有 "+i(_.value.length-o.value.length)+" 个文件未展开显示 ",1)):F("",!0)],64)):(c(),d("span",We,"暂未选择文件"))])]),e[15]||(e[15]=a("div",{class:"section-title"},"筛选条件",-1)),a("div",Xe,[a("div",Ze,[e[6]||(e[6]=a("label",{class:"filter-label"},"金额(手动输入)",-1)),Y(a("input",{"onUpdate:modelValue":e[0]||(e[0]=t=>f.amount=t),type:"number",step:"0.01",min:"0",class:"filter-input",placeholder:"例如:59.99"},null,512),[[ne,f.amount,void 0,{number:!0}]])]),a("div",et,[e[7]||(e[7]=a("label",{class:"filter-label"},"排名",-1)),Y(a("input",{"onUpdate:modelValue":e[1]||(e[1]=t=>f.rank=t),type:"number",step:"1",min:"0",class:"filter-input",placeholder:"例如:100000"},null,512),[[ne,f.rank,void 0,{number:!0}]])]),a("div",tt,[a("label",st,[Y(a("input",{type:"checkbox",class:"filter-check-input","onUpdate:modelValue":e[2]||(e[2]=t=>f.fba=t)},null,512),[[le,f.fba]]),e[8]||(e[8]=a("span",{class:"filter-check-text"},"FBA",-1))]),a("label",at,[Y(a("input",{type:"checkbox",class:"filter-check-input","onUpdate:modelValue":e[3]||(e[3]=t=>f.fbm=t)},null,512),[[le,f.fbm]]),e[9]||(e[9]=a("span",{class:"filter-check-text"},"FBM",-1))])])]),a("div",nt,[e[10]||(e[10]=a("span",null,"国家与顺序",-1)),K.value?(c(),d("span",lt,"保存中…")):F("",!0)]),e[16]||(e[16]=a("p",{class:"hint country-pref-hint"},[re(" 勾选需要采集的国家(暂定 5 国,至少保留 1 个);上方勾选区"),a("strong",null,"先按已选顺序"),re("排列,其余未选国家排在后面。拖拽下方列表可调整顺序。 ")],-1)),a("div",rt,[(c(!0),d(G,null,O(z.value,t=>(c(),d("label",{key:t.code,class:"country-check-row"},[a("input",{type:"checkbox",class:"country-check-input",checked:H(t.code),disabled:C(t.code),onChange:r=>R(t.code,r)},null,40,ot),a("span",it,i(t.label)+"("+i(t.code)+")",1)]))),128))]),l.value.length?(c(),d("div",ut,[e[12]||(e[12]=a("div",{class:"country-order-caption"},"已选顺序(拖拽 ⋮⋮ 调整)",-1)),a("div",ct,[(c(!0),d(G,null,O(l.value,(t,r)=>(c(),d("div",{key:t,class:ie(["country-drag-row",{dragging:b.value===r}]),draggable:"true",onDragstart:y=>q(r),onDragend:fe,onDragover:e[4]||(e[4]=oe(()=>{},["prevent"])),onDrop:oe(y=>ve(r),["prevent"])},[e[11]||(e[11]=a("span",{class:"drag-handle",title:"拖动排序"},"⋮⋮",-1)),a("span",ft,i(L(t))+"("+i(t)+")",1)],42,dt))),128))])])):F("",!0),a("div",vt,[a("button",{type:"button",class:"btn-run",disabled:p.value||!S.value.length,onClick:ke},i(p.value?"提交中...":"提交采集任务"),9,pt),a("button",{type:"button",class:"btn-run btn-queue",disabled:w.value||!I.value,onClick:me},i(w.value?"推送中...":"推送到 Python 队列"),9,yt)]),e[17]||(e[17]=a("p",{class:"loading-msg"},"提交后由 Java 解析 Excel 并落库为待采集任务(PENDING);推送到 Python 队列将激活任务(RUNNING),Python 端按 50 条/页拉取明细执行采集。",-1)),M.value?(c(),d("div",ht,[e[13]||(e[13]=a("div",{class:"section-title queue-debug-title"},"推送结果",-1)),a("div",gt,i(M.value),1),D.value?(c(),d("pre",kt,i(D.value),1)):F("",!0)])):F("",!0)]),a("section",mt,[e[25]||(e[25]=a("div",{class:"panel-header"},"采集数据",-1)),a("div",bt,[a("div",_t,[a("div",wt,[e[18]||(e[18]=a("span",{class:"summary-label"},"运行中任务",-1)),a("strong",null,i(x.value.pendingTaskCount),1)]),a("div",Ct,[e[19]||(e[19]=a("span",{class:"summary-label"},"已结束任务",-1)),a("strong",null,i(x.value.processedTaskCount),1)]),a("div",St,[e[20]||(e[20]=a("span",{class:"summary-label"},"成功任务",-1)),a("strong",null,i(x.value.successTaskCount),1)]),a("div",It,[e[21]||(e[21]=a("span",{class:"summary-label"},"失败任务",-1)),a("strong",null,i(x.value.failedTaskCount),1)])]),e[24]||(e[24]=a("div",{class:"subsection-title"},"匹配任务",-1)),a("div",Tt,[e[22]||(e[22]=a("div",{class:"result-list-header"},[a("span",null,"当前任务")],-1)),$.value.length?(c(),d("ul",Pt,[(c(!0),d(G,null,O($.value,t=>(c(),d("li",{key:`cur-${t.taskId}`,class:"task-item"},[a("div",Et,[a("span",Dt,i(t.sourceFilename||"采集数据"),1),a("div",xt,"任务 ID:"+i(t.taskId),1),a("div",Ft,"开始时间:"+i(W(t.startedAt||t.createdAt)),1),a("div",At,"行数:"+i(t.rowCount??"-"),1)]),a("div",Ut,[a("span",$t,i(se(t)),1),a("button",{type:"button",class:"btn-delete",onClick:r=>ae(t)},"删除",8,Lt)])]))),128))])):(c(),d("div",Nt,"暂无当前任务"))]),a("div",Rt,[e[23]||(e[23]=a("div",{class:"result-list-header"},[a("span",null,"历史记录")],-1)),E.value.length?(c(),d("ul",Mt,[(c(!0),d(G,null,O(E.value,t=>(c(),d("li",{key:`his-${t.resultId}-${t.taskId}`,class:"task-item"},[a("div",qt,[a("span",Gt,i(t.sourceFilename||"采集数据"),1),a("div",Kt,"任务 ID:"+i(t.taskId??"-"),1),a("div",Vt,"开始时间:"+i(W(t.startedAt||t.createdAt)),1),a("div",Ot,"结束时间:"+i(W(t.finishedAt)),1),t.resultFilename?(c(),d("div",zt,i(t.resultFilename),1)):F("",!0),t.error?(c(),d("div",Ht,"错误:"+i(t.error),1)):F("",!0)]),a("div",Jt,[a("span",{class:ie(["status",be(t)])},i(se(t)),3),t.resultId?(c(),d("button",{key:0,type:"button",class:"btn-delete",onClick:r=>ae(t)},"删除",8,jt)):F("",!0)])]))),128))])):(c(),d("div",Bt,"暂无历史记录"))])])])])]))}}),Wt=Re(Qt,[["__scopeId","data-v-14b8e8a2"]]);Be(Wt).use(Me).mount("#app"); +import{g as m,bB as fe,bC as oe,V as ve,d as pe,o as me,a as f,c as v,b as ye,B as he,e as t,F as K,r as Y,t as i,f as B,w as O,H as ae,v as X,n as ne,bD as ke,h as le,bE as ge,E as y,bF as be,i as Q,bG as _e,bH as we,bI as Ce,bJ as Se,bK as Ie,bL as Te,bM as Ne,_ as Pe,q as xe,u as Ee}from"./java-modules-B8c-YG5x.js";import{e as Ae}from"./brand-COze15GJ.js";import{c as re}from"./categorized-timers-JPA-olTr.js";const De=u=>u==="SUCCESS"||u==="FAILED";function Fe(u){if(!u||typeof window>"u")return[];try{const k=window.localStorage.getItem(u);if(!k)return[];const g=JSON.parse(k);return Array.isArray(g)?g.filter(_=>typeof _=="number"&&_>0):[]}catch{return[]}}function Ue(u,k){if(!(!u||typeof window>"u"))try{k.length===0?window.localStorage.removeItem(u):window.localStorage.setItem(u,JSON.stringify(k))}catch{}}function $e(u){const k=re(`task-progress-loop:${u.scope}`),g=u.isTerminal??De,_=u.getIntervalMs??ve,d=m(Fe(u.storageKey)),b=m({}),l=m(!1);let c=null,S=!1;function L(){Ue(u.storageKey,d.value)}function G(n){!Number.isFinite(n)||n<=0||d.value.includes(n)||(d.value=[...d.value,n],L(),A(!0))}function F(n){if(d.value.includes(n)&&(d.value=d.value.filter(o=>o!==n),L(),b.value[n])){const o={...b.value};delete o[n],b.value=o}}function T(n){const o=Array.from(new Set(n.filter(M=>Number.isFinite(M)&&M>0)));d.value=o,L()}function w(n){const o=b.value[n];return!!o&&g(o)}async function N(){if(S)return;const n=d.value.filter(o=>o>0);if(n.length){l.value=!0;try{const M=(await u.fetchProgress(n))?.items||[],z=[],H={...b.value};for(const C of M){const D=u.extractTaskId(C);if(typeof D!="number"||D<=0)continue;const q=u.extractStatus(C)||"";try{u.onUpdate?.(D,C)}catch{}q&&(H[D]=q,g(q)&&z.push({taskId:D,detail:C,status:q}))}b.value=H;for(const C of z){F(C.taskId);try{await u.onTerminal?.(C.taskId,C.detail,C.status)}catch{}}}catch(o){u.onError?.(o)}finally{l.value=!1}}}function R(){c!=null&&(k.clearTimer("task-poll",c),c=null)}function E(n=!1){if(S||c!=null&&!n)return;R();const o=async()=>{if(c=null,!S&&d.value.length){if(l.value){c=k.setTimeout("task-poll",o,500);return}await N(),!S&&d.value.length>0&&(c=k.setTimeout("task-poll",o,_()))}};n?o():c=k.setTimeout("task-poll",o,_())}function A(n=!1){S||d.value.length&&(c!=null&&!n||E(n))}function U(){R()}fe(d,(n,o)=>{if(!S){if(!n.length){U();return}(!o||o.length===0)&&E(!0)}},{flush:"post"});let P=null;typeof document<"u"&&(P=()=>{document.visibilityState==="visible"&&d.value.length>0&&E(!0)},document.addEventListener("visibilitychange",P));function I(){S||(S=!0,U(),k.clearScope(),P&&typeof document<"u"&&(document.removeEventListener("visibilitychange",P),P=null))}return oe(()=>I()),d.value.length>0&&E(!0),{taskIds:d,taskStatuses:b,inFlight:l,add:G,remove:F,reset:T,ensure:A,stop:U,refreshOnce:N,isTerminal:w,dispose:I}}const Be={class:"page-shell module-page"},Le={class:"main-content"},Re={class:"left-panel"},Me={class:"upload-zone"},qe={class:"selected-files"},Ge={key:0,class:"more-line"},Ve={key:1},Ke={class:"filter-zone"},Oe={class:"filter-row"},ze={class:"range-inputs"},He={class:"filter-checks"},Je={class:"filter-check-row"},je={class:"filter-check-row"},Ye={class:"filter-check-row"},Qe={class:"section-title country-section-title"},We={key:0,class:"country-pref-saving"},Xe={class:"country-pref-radios"},Ze=["checked","onChange"],et={class:"country-check-text"},tt={class:"run-row"},st=["disabled"],at=["disabled"],nt={key:0,class:"queue-debug-card"},lt={class:"queue-debug-line"},ot={key:0,class:"queue-debug-payload"},rt={class:"right-panel"},it={class:"task-list-wrap"},ut={class:"clean-result-summary"},ct={class:"summary-card"},dt={class:"summary-card"},ft={class:"summary-card"},vt={class:"summary-card"},pt={class:"result-list-wrap"},mt={key:0,class:"empty-tasks"},yt={key:1,class:"task-list clean-result-list"},ht={class:"left"},kt={class:"id"},gt={class:"files"},bt={class:"files"},_t={class:"files"},wt={class:"task-right"},Ct={class:"status running"},St=["onClick"],It={class:"result-list-wrap"},Tt={key:0,class:"empty-tasks"},Nt={key:1,class:"task-list clean-result-list"},Pt={class:"left"},xt={class:"id"},Et={class:"files"},At={class:"files"},Dt={class:"files"},Ft={key:0,class:"files"},Ut={key:1,class:"files"},$t={class:"task-right"},Bt=["onClick"],Lt="brand:collect-data:polling-task-ids",Rt=pe({__name:"BrandCollectDataTab",setup(u){const k=[{code:"DE",label:"德国"},{code:"UK",label:"英国"},{code:"FR",label:"法国"},{code:"IT",label:"意大利"},{code:"ES",label:"西班牙"}],g=m([]),_=m([]),d=m(!1),b=m(!1),l=ke({minAmount:null,maxAmount:null,rank:!1,fba:!1,fbm:!1}),c=m("DE"),S=le(()=>c.value?[c.value]:[]),L=m(!1),G=m(!1),F=re("collect-data-tab");let T=null;const w=m(null),N=m(null),R=m(""),E=m(""),A=m({pendingTaskCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),U=m([]),P=m([]),I=m({}),n=$e({scope:"collect-data-tab",storageKey:Lt,fetchProgress:a=>Ne(a),extractTaskId:a=>a.task?.id??null,extractStatus:a=>a.task?.status??"",onUpdate:(a,e)=>{const s=I.value[a];I.value={...I.value,[a]:s?{...s,task:{...s.task||{},...e.task||{}},items:e.items??s.items}:e}},onTerminal:async a=>{if(I.value[a]){const e={...I.value};delete e[a],I.value=e}await Promise.all([V(),J()])}}),o=le(()=>g.value.slice(0,8));function M(a){k.some(e=>e.code===a)&&c.value!==a&&(L.value=!0,c.value=a,z())}function z(){T!=null&&F.clearTimer("country-pref-save",T),T=F.setTimeout("country-pref-save",()=>{T=null,H()},450)}async function H(){if(c.value){G.value=!0;try{await ge([c.value])}catch(a){y.error(a instanceof Error?a.message:"保存国家顺序失败")}finally{G.value=!1}}}async function C(){try{const a=await be();if(L.value)return;const e=a?.country_codes;Array.isArray(e)&&e.length&&(c.value=String(e[0]||"DE"))}catch{}}async function D(a){const e=Q();if(!e?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传能力");const s=[];for(const p of a){const x=typeof p=="string"?p:p.absolutePath,$=typeof p=="string"?void 0:p.relativePath,r=await e.upload_file_to_java(x,$);if(!r?.success||!r.data)throw new Error(r?.error||r?.message||`上传失败:${x}`);s.push(r.data)}return s}async function q(){const a=Q();if(!a?.select_brand_xlsx_files||!a.upload_file_to_java){y.warning("当前环境不支持文件选择或上传");return}try{const e=await a.select_brand_xlsx_files();if(!e?.length)return;const s=await D(e);_.value=s,g.value=s.map(p=>p.relativePath||p.originalFilename||p.fileKey),w.value=null,N.value=null}catch(e){y.error(e instanceof Error?e.message:"文件选择失败")}}async function ie(){const a=Q();if(!a?.select_brand_folder){y.warning("当前环境不支持文件夹选择,请在本地客户端中打开");return}try{const e=await a.select_brand_folder();if(!e)return;const s=await Ae(e);if(!s.success||!s.items?.length){y.warning(s.error||"该文件夹下没有可用的 xlsx 文件");return}const p=await D(s.items);_.value=p,g.value=s.items.map(x=>x.relativePath||x.absolutePath),w.value=null,N.value=null,y.success(`已选择文件夹内 ${s.items.length} 个 Excel 文件`)}catch(e){y.error(e instanceof Error?e.message:"选择失败")}}function Z(){const a=l.minAmount===null||l.minAmount===void 0||Number.isNaN(l.minAmount)?null:l.minAmount,e=l.maxAmount===null||l.maxAmount===void 0||Number.isNaN(l.maxAmount)?null:l.maxAmount;return{amount:e??a,minAmount:a,maxAmount:e,min_amount:a,max_amount:e,rank:!!l.rank,fba:!!l.fba,fbm:!!l.fbm,countryCodes:[...S.value],countryCode:c.value,country_code:c.value}}async function ue(){if(!_.value.length){y.warning("请先选择 Excel 文件");return}if(!c.value){y.warning("请选择采集国家");return}d.value=!0;try{const a=await _e({files:_.value.map(e=>({fileKey:e.fileKey,originalFilename:e.originalFilename,relativePath:e.relativePath})),task_type:"collect-data",filters:Z()});N.value=a,w.value=a.taskId??null,a.taskId&&n.add(a.taskId),y.success(`提交成功:任务 ${a.taskNo||a.taskId},落库 ${a.acceptedRows??0} 行`),await Promise.all([V(),J()])}catch(a){y.error(a instanceof Error?a.message:"提交失败")}finally{d.value=!1}}async function ce(){if(!w.value){y.warning("请先提交采集任务");return}const a=Q();if(!a?.enqueue_json){y.warning("当前环境未提供 Python 队列能力");return}b.value=!0;try{await we(w.value);const e={type:"collect-data-run",ts:Date.now(),data:{taskId:w.value,taskNo:N.value?.taskNo,taskType:"collect-data",totalRows:N.value?.acceptedRows??0,pageSize:N.value?.pageSize??50,filters:Z()}},s=await a.enqueue_json(e);if(!s?.success)throw new Error(s?.error||"入队失败");R.value=`已推送至 Python 队列(队列长度:${s.queue_size??"-"})`,E.value=JSON.stringify(e,null,2),w.value&&n.add(w.value),y.success("已推送到 Python 队列"),await V()}catch(e){y.error(e instanceof Error?e.message:"推送失败")}finally{b.value=!1}}function W(a){if(!a)return"-";const e=new Date(a);if(Number.isNaN(e.getTime()))return a;const s=e.getFullYear(),p=String(e.getMonth()+1).padStart(2,"0"),x=String(e.getDate()).padStart(2,"0"),$=String(e.getHours()).padStart(2,"0"),r=String(e.getMinutes()).padStart(2,"0"),h=String(e.getSeconds()).padStart(2,"0");return`${s}-${p}-${x} ${$}:${r}:${h}`}function ee(a){return(a.taskStatus||"").toUpperCase()}function te(a){const e=ee(a);return e==="RUNNING"?"执行中":e==="PENDING"?"等待中":e==="SUCCESS"||a.success?"已完成":e==="FAILED"?"失败":"等待中"}function de(a){const e=ee(a);return e==="RUNNING"?"running":e==="FAILED"?"failed":e==="SUCCESS"||a.success?"success":"pending"}async function V(){try{A.value=await Ce()}catch{}}async function J(){try{const e=(await Se(50)).items||[],s=e.filter(r=>{const h=(r.taskStatus||"").toUpperCase();return h==="PENDING"||h==="RUNNING"});P.value=e.filter(r=>{const h=(r.taskStatus||"").toUpperCase();return h==="SUCCESS"||h==="FAILED"});const p=new Set;for(const r of s)r.taskId&&(p.add(r.taskId),n.add(r.taskId));for(const r of[...n.taskIds.value])e.some(j=>j.taskId===r)||n.remove(r);const x=new Set(s.map(r=>r.taskId).filter(r=>typeof r=="number")),$=[...s];for(const r of n.taskIds.value){if(x.has(r))continue;const h=I.value[r],j=h?.items?.[0];j?$.push(j):h?.task&&$.push({taskId:h.task.id,taskNo:h.task.taskNo,taskStatus:h.task.status,startedAt:h.task.createdAt,finishedAt:h.task.finishedAt,sourceFilename:"采集数据"})}U.value=$}catch{}}async function se(a){try{if(a.resultId)await Ie(a.resultId);else if(a.taskId)await Te(a.taskId);else return;a.taskId&&n.remove(a.taskId),y.success("已删除"),await Promise.all([V(),J()])}catch(e){y.error(e instanceof Error?e.message:"删除失败")}}return me(()=>{C(),V(),J()}),oe(()=>{T!=null&&(F.clearTimer("country-pref-save",T),T=null),F.clearScope()}),(a,e)=>(f(),v("div",Be,[ye(he,{active:"collect-data"}),t("div",Le,[t("aside",Re,[e[13]||(e[13]=t("div",{class:"section-title"},"上传文件",-1)),t("div",Me,[e[5]||(e[5]=t("div",{class:"hint"},"选择需要采集的 Excel 文件或文件夹(默认根目录:采集前数据.xlsx),后续将按下方筛选条件交给 Python 端进行数据采集。",-1)),t("div",{class:"btns"},[t("button",{type:"button",class:"opt-btn",onClick:q},"选择 Excel"),t("button",{type:"button",class:"opt-btn",onClick:ie},"选择文件夹")]),t("div",qe,[g.value.length?(f(),v(K,{key:0},[(f(!0),v(K,null,Y(o.value,s=>(f(),v("span",{key:s},i(s),1))),128)),g.value.length>o.value.length?(f(),v("span",Ge," 还有 "+i(g.value.length-o.value.length)+" 个文件未展开显示 ",1)):B("",!0)],64)):(f(),v("span",Ve,"暂未选择文件"))])]),e[14]||(e[14]=t("div",{class:"section-title"},"筛选条件",-1)),t("div",Ke,[t("div",Oe,[e[7]||(e[7]=t("label",{class:"filter-label"},"金额区间",-1)),t("div",ze,[O(t("input",{"onUpdate:modelValue":e[0]||(e[0]=s=>l.minAmount=s),type:"number",step:"0.01",min:"0",class:"filter-input",placeholder:"最低"},null,512),[[ae,l.minAmount,void 0,{number:!0}]]),e[6]||(e[6]=t("span",{class:"range-separator"},"至",-1)),O(t("input",{"onUpdate:modelValue":e[1]||(e[1]=s=>l.maxAmount=s),type:"number",step:"0.01",min:"0",class:"filter-input",placeholder:"最高"},null,512),[[ae,l.maxAmount,void 0,{number:!0}]])])]),t("div",He,[t("label",Je,[O(t("input",{type:"checkbox",class:"filter-check-input","onUpdate:modelValue":e[2]||(e[2]=s=>l.rank=s)},null,512),[[X,l.rank]]),e[8]||(e[8]=t("span",{class:"filter-check-text"},"排名",-1))]),t("label",je,[O(t("input",{type:"checkbox",class:"filter-check-input","onUpdate:modelValue":e[3]||(e[3]=s=>l.fba=s)},null,512),[[X,l.fba]]),e[9]||(e[9]=t("span",{class:"filter-check-text"},"FBA",-1))]),t("label",Ye,[O(t("input",{type:"checkbox",class:"filter-check-input","onUpdate:modelValue":e[4]||(e[4]=s=>l.fbm=s)},null,512),[[X,l.fbm]]),e[10]||(e[10]=t("span",{class:"filter-check-text"},"FBM",-1))])])]),t("div",Qe,[e[11]||(e[11]=t("span",null,"采集国家",-1)),G.value?(f(),v("span",We,"保存中…")):B("",!0)]),e[15]||(e[15]=t("p",{class:"hint country-pref-hint"}," 每次任务只采集一个国家,选择后会自动保存,下次进入默认使用该国家。 ",-1)),t("div",Xe,[(f(),v(K,null,Y(k,s=>t("label",{key:s.code,class:ne(["country-check-row",{selected:c.value===s.code}])},[t("input",{type:"radio",name:"collect-data-country",class:"country-check-input",checked:c.value===s.code,onChange:p=>M(s.code)},null,40,Ze),t("span",et,i(s.label)+"("+i(s.code)+")",1)],2)),64))]),t("div",tt,[t("button",{type:"button",class:"btn-run",disabled:d.value||!_.value.length,onClick:ue},i(d.value?"提交中...":"提交采集任务"),9,st),t("button",{type:"button",class:"btn-run btn-queue",disabled:b.value||!w.value,onClick:ce},i(b.value?"推送中...":"推送到 Python 队列"),9,at)]),e[16]||(e[16]=t("p",{class:"loading-msg"},"提交后由 Java 解析 Excel 并落库为待采集任务(PENDING);推送到 Python 队列将激活任务(RUNNING),Python 端按 50 条/页拉取明细执行采集。",-1)),R.value?(f(),v("div",nt,[e[12]||(e[12]=t("div",{class:"section-title queue-debug-title"},"推送结果",-1)),t("div",lt,i(R.value),1),E.value?(f(),v("pre",ot,i(E.value),1)):B("",!0)])):B("",!0)]),t("section",rt,[e[24]||(e[24]=t("div",{class:"panel-header"},"采集数据",-1)),t("div",it,[t("div",ut,[t("div",ct,[e[17]||(e[17]=t("span",{class:"summary-label"},"运行中任务",-1)),t("strong",null,i(A.value.pendingTaskCount),1)]),t("div",dt,[e[18]||(e[18]=t("span",{class:"summary-label"},"已结束任务",-1)),t("strong",null,i(A.value.processedTaskCount),1)]),t("div",ft,[e[19]||(e[19]=t("span",{class:"summary-label"},"成功任务",-1)),t("strong",null,i(A.value.successTaskCount),1)]),t("div",vt,[e[20]||(e[20]=t("span",{class:"summary-label"},"失败任务",-1)),t("strong",null,i(A.value.failedTaskCount),1)])]),e[23]||(e[23]=t("div",{class:"subsection-title"},"匹配任务",-1)),t("div",pt,[e[21]||(e[21]=t("div",{class:"result-list-header"},[t("span",null,"当前任务")],-1)),U.value.length?(f(),v("ul",yt,[(f(!0),v(K,null,Y(U.value,s=>(f(),v("li",{key:`cur-${s.taskId}`,class:"task-item"},[t("div",ht,[t("span",kt,i(s.sourceFilename||"采集数据"),1),t("div",gt,"任务 ID:"+i(s.taskId),1),t("div",bt,"开始时间:"+i(W(s.startedAt||s.createdAt)),1),t("div",_t,"行数:"+i(s.rowCount??"-"),1)]),t("div",wt,[t("span",Ct,i(te(s)),1),t("button",{type:"button",class:"btn-delete",onClick:p=>se(s)},"删除",8,St)])]))),128))])):(f(),v("div",mt,"暂无当前任务"))]),t("div",It,[e[22]||(e[22]=t("div",{class:"result-list-header"},[t("span",null,"历史记录")],-1)),P.value.length?(f(),v("ul",Nt,[(f(!0),v(K,null,Y(P.value,s=>(f(),v("li",{key:`his-${s.resultId}-${s.taskId}`,class:"task-item"},[t("div",Pt,[t("span",xt,i(s.sourceFilename||"采集数据"),1),t("div",Et,"任务 ID:"+i(s.taskId??"-"),1),t("div",At,"开始时间:"+i(W(s.startedAt||s.createdAt)),1),t("div",Dt,"结束时间:"+i(W(s.finishedAt)),1),s.resultFilename?(f(),v("div",Ft,i(s.resultFilename),1)):B("",!0),s.error?(f(),v("div",Ut,"错误:"+i(s.error),1)):B("",!0)]),t("div",$t,[t("span",{class:ne(["status",de(s)])},i(te(s)),3),s.resultId?(f(),v("button",{key:0,type:"button",class:"btn-delete",onClick:p=>se(s)},"删除",8,Bt)):B("",!0)])]))),128))])):(f(),v("div",Tt,"暂无历史记录"))])])])])]))}}),Mt=Pe(Rt,[["__scopeId","data-v-421c638b"]]);xe(Mt).use(Ee).mount("#app"); diff --git a/app/assets/convert.js b/app/assets/convert.js index f059e4e..ddb3af9 100644 --- a/app/assets/convert.js +++ b/app/assets/convert.js @@ -1 +1 @@ -import{d as A,o as H,a as n,c as o,b as z,B as K,e as s,F as w,r as x,t as i,f as _,n as P,w as M,x as j,y as q,g as u,h as E,z as G,i as F,E as r,A as J,C as L,D as O,G as W,s as Q,_ as X,q as Y,u as Z}from"./java-modules-DzYrjxib.js";import{e as ee}from"./brand-jr47vQUd.js";const se={class:"page-shell module-page"},te={class:"main-content"},ae={class:"left-panel"},le={class:"upload-zone"},ne={class:"selected-files clean-placeholder"},oe={key:0,class:"more-line"},re={key:1},ie={class:"option-group"},ce=["value"],ue={class:"template-item-content"},de={class:"label"},ve={key:0,class:"template-tag"},pe={key:1,class:"template-tag muted"},_e={key:2,class:"template-tag custom"},fe={class:"desc"},me={key:0,class:"empty-option"},he={class:"option-group"},ye={class:"radio-item active"},ge={class:"desc"},be={class:"run-row"},we=["disabled"],ke={class:"loading-msg"},Ce={class:"right-panel"},xe={class:"task-list-wrap"},Fe={class:"clean-result-summary"},Ie={class:"summary-card"},Pe={class:"summary-card"},Ee={class:"summary-card"},Te={class:"result-list-wrap"},Be={key:0,class:"empty-tasks"},De={key:1,class:"task-list clean-result-list"},$e={class:"left"},Ne=["title"],Re={key:0,class:"files"},Se={key:1,class:"files"},Ue={class:"task-right"},Ve=["onClick"],Ae=["onClick"],He=A({__name:"BrandConvertTab",setup(Ke){const v=u([]),g=u(""),f=u([]),m=u(!1),b=u([]),h=u({total:0,successCount:0,failedCount:0,items:[]}),d=u([]),c=u(""),k=E(()=>v.value.slice(0,8)),T=E(()=>d.value.find(a=>a.id===c.value)||null);async function I(a){const e=F();if(!e?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const l of a){const p=typeof l=="string"?l:l.absolutePath,V=typeof l=="string"?void 0:l.relativePath,y=await e.upload_file_to_java(p,V);if(!y?.success||!y.data)throw new Error(y?.error||y?.message||`上传失败:${p}`);t.push(y.data)}return t}async function B(a){const e=await G();d.value=e||[];const t=d.value.find(p=>p.id===c.value);if(t){c.value=t.id;return}const l=d.value.find(p=>p.isDefault);if(l){c.value=l.id;return}c.value=d.value[0]?.id||""}async function D(a,e){v.value=a,g.value="",f.value=await I(a),r.success(e)}async function $(){const a=F();if(!a?.select_brand_xlsx_files){r.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const e=await a.select_brand_xlsx_files();if(!e?.length)return;await D(e,`已选择 ${e.length} 个待转换文件`)}catch(e){r.error(e instanceof Error?e.message:"选择失败")}}async function N(){const a=F();if(!a?.select_brand_folder){r.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const e=await a.select_brand_folder();if(!e)return;g.value=e.split(/[/\\]/).filter(Boolean).pop()||"";const t=await ee(e);if(t.success&&t.items?.length){v.value=t.items.map(l=>l.relativePath),f.value=await I(t.items),r.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`);return}r.warning(t.error||"该文件夹下没有 xlsx 文件")}catch(e){r.error(e instanceof Error?e.message:"选择失败")}}async function R(){if(!f.value.length){r.warning("请先选择待转换 Excel 文件或文件夹");return}if(!c.value){r.warning("请先选择模板");return}try{m.value=!0;const a=await J({files:f.value.map(e=>({fileKey:e.fileKey,originalFilename:e.originalFilename,relativePath:e.relativePath})),templateId:c.value,archiveName:f.value.some(e=>!!e.relativePath)&&g.value?g.value:void 0});h.value=a,b.value=a.items||[],await C(),r.success("格式转换完成")}catch(a){r.error(a instanceof Error?a.message:"格式转换失败")}finally{m.value=!1}}async function C(){try{const a=await L();b.value=a.items||[],h.value={total:a.items?.length||0,successCount:a.items?.filter(e=>e.success).length||0,failedCount:a.items?.filter(e=>!e.success).length||0,items:a.items||[]}}catch{}}async function S(a){try{await O(a),await C(),r.success("已删除")}catch(e){r.error(e instanceof Error?e.message:"删除失败")}}async function U(a){const e=a.downloadUrl||(a.resultId?W(a.resultId):"");if(!e){r.warning("当前结果没有下载地址");return}const t=a.outputFilename||`${new Date().toISOString().slice(0,10).replace(/-/g,"")}.txt`,l=await Q(e,t,a.resultId?`convert:${a.resultId}`:void 0);l.success?r.success(`已保存:${l.path||t}`):l.error&&l.error!=="用户取消"&&r.error(l.error)}return H(()=>{B().catch(()=>{}),C().catch(()=>{})}),(a,e)=>(n(),o("div",se,[z(K,{active:"convert"}),s("div",te,[s("aside",ae,[e[5]||(e[5]=s("div",{class:"section-title"},"选择文件",-1)),s("div",le,[e[1]||(e[1]=s("div",{class:"hint"},"选择需要转换的 Excel 文件或文件夹,将按所选模板生成 txt 文件。",-1)),s("div",{class:"btns"},[s("button",{type:"button",class:"opt-btn",onClick:$},"选择 Excel 文件"),s("button",{type:"button",class:"opt-btn",onClick:N},"选择文件夹")]),s("div",ne,[v.value.length?(n(),o(w,{key:0},[(n(!0),o(w,null,x(k.value,t=>(n(),o("span",{key:t},i(t),1))),128)),v.value.length>k.value.length?(n(),o("span",oe," 还有 "+i(v.value.length-k.value.length)+" 个文件未展开显示 ",1)):_("",!0)],64)):(n(),o("span",re,"暂未选择待转换文件"))])]),e[6]||(e[6]=s("div",{class:"section-title"},"模板选择",-1)),s("div",ie,[(n(!0),o(w,null,x(d.value,t=>(n(),o("label",{key:t.id,class:P(["radio-item",{active:c.value===t.id}])},[M(s("input",{"onUpdate:modelValue":e[0]||(e[0]=l=>c.value=l),type:"radio",value:t.id,name:"convert-template"},null,8,ce),[[j,c.value]]),s("div",ue,[s("div",null,[s("span",de,[q(i(t.templateName)+" ",1),t.isDefault?(n(),o("span",ve,"默认")):t.builtIn?(n(),o("span",pe,"内置")):(n(),o("span",_e,"自定义"))]),s("div",fe,"输出文件:"+i(t.outputFilename),1)])])],2))),128)),d.value.length?_("",!0):(n(),o("div",me,"暂无可用模板"))]),e[7]||(e[7]=s("div",{class:"section-title"},"转换说明",-1)),s("div",he,[s("label",ye,[e[3]||(e[3]=s("input",{type:"checkbox",checked:"",disabled:""},null,-1)),s("div",null,[e[2]||(e[2]=s("span",{class:"label"},"按当前模板输出",-1)),s("div",ge,"当前模板:"+i(T.value?.templateName||"未加载模板"),1)])]),e[4]||(e[4]=s("label",{class:"radio-item active"},[s("input",{type:"checkbox",checked:"",disabled:""}),s("div",null,[s("span",{class:"label"},"SKU 使用雪花ID-序号"),s("div",{class:"desc"},"例如 1773816146796-1")])],-1))]),s("div",be,[s("button",{type:"button",class:"btn-run",disabled:m.value,onClick:R},i(m.value?"转换中...":"开始转换"),9,we),s("span",ke,i(m.value?"正在生成并上传结果,请稍候…":"选择文件后即可执行格式转换,结果会显示在右侧供下载"),1)])]),s("section",Ce,[e[12]||(e[12]=s("div",{class:"panel-header"},"转换结果",-1)),s("div",xe,[s("div",Fe,[s("div",Ie,[e[8]||(e[8]=s("span",{class:"summary-label"},"已处理文件",-1)),s("strong",null,i(h.value.total),1)]),s("div",Pe,[e[9]||(e[9]=s("span",{class:"summary-label"},"成功结果",-1)),s("strong",null,i(h.value.successCount),1)]),s("div",Ee,[e[10]||(e[10]=s("span",{class:"summary-label"},"失败文件",-1)),s("strong",null,i(h.value.failedCount),1)])]),s("div",Te,[e[11]||(e[11]=s("div",{class:"result-list-header"},[s("span",null,"生成的结果压缩包列表")],-1)),b.value.length===0?(n(),o("div",Be," 暂无转换结果,完成格式转换后会在这里展示结果压缩包 ")):(n(),o("ul",De,[(n(!0),o(w,null,x(b.value,t=>(n(),o("li",{key:`${t.resultId||t.outputFilename||t.sourceFilename}`,class:"task-item"},[s("div",$e,[s("span",{class:"id",title:t.sourceFilename},i(t.sourceFilename||"-"),9,Ne),t.outputFilename?(n(),o("div",Re,"压缩包文件:"+i(t.outputFilename),1)):_("",!0),t.error?(n(),o("div",Se,"错误信息:"+i(t.error),1)):_("",!0)]),s("div",Ue,[s("span",{class:P(["status",t.success?"success":"failed"])},i(t.success?"已完成":"失败"),3),t.success&&(t.downloadUrl||t.resultId)?(n(),o("button",{key:0,type:"button",class:"download",onClick:l=>U(t)}," 下载压缩包 ",8,Ve)):_("",!0),t.resultId?(n(),o("button",{key:1,type:"button",class:"btn-delete",onClick:l=>S(t.resultId)}," 删除 ",8,Ae)):_("",!0)])]))),128))]))])])])])]))}}),ze=X(He,[["__scopeId","data-v-64f58715"]]);Y(ze).use(Z).mount("#app"); +import{d as A,o as H,a as n,c as o,b as z,B as K,e as s,F as w,r as x,t as i,f as _,n as P,w as M,x as j,y as q,g as u,h as E,z as G,i as F,E as r,A as J,C as L,D as O,G as W,s as Q,_ as X,q as Y,u as Z}from"./java-modules-B8c-YG5x.js";import{e as ee}from"./brand-COze15GJ.js";const se={class:"page-shell module-page"},te={class:"main-content"},ae={class:"left-panel"},le={class:"upload-zone"},ne={class:"selected-files clean-placeholder"},oe={key:0,class:"more-line"},re={key:1},ie={class:"option-group"},ce=["value"],ue={class:"template-item-content"},de={class:"label"},ve={key:0,class:"template-tag"},pe={key:1,class:"template-tag muted"},_e={key:2,class:"template-tag custom"},fe={class:"desc"},me={key:0,class:"empty-option"},he={class:"option-group"},ye={class:"radio-item active"},ge={class:"desc"},be={class:"run-row"},we=["disabled"],ke={class:"loading-msg"},Ce={class:"right-panel"},xe={class:"task-list-wrap"},Fe={class:"clean-result-summary"},Ie={class:"summary-card"},Pe={class:"summary-card"},Ee={class:"summary-card"},Te={class:"result-list-wrap"},Be={key:0,class:"empty-tasks"},De={key:1,class:"task-list clean-result-list"},$e={class:"left"},Ne=["title"],Re={key:0,class:"files"},Se={key:1,class:"files"},Ue={class:"task-right"},Ve=["onClick"],Ae=["onClick"],He=A({__name:"BrandConvertTab",setup(Ke){const v=u([]),g=u(""),f=u([]),m=u(!1),b=u([]),h=u({total:0,successCount:0,failedCount:0,items:[]}),d=u([]),c=u(""),k=E(()=>v.value.slice(0,8)),T=E(()=>d.value.find(a=>a.id===c.value)||null);async function I(a){const e=F();if(!e?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const l of a){const p=typeof l=="string"?l:l.absolutePath,V=typeof l=="string"?void 0:l.relativePath,y=await e.upload_file_to_java(p,V);if(!y?.success||!y.data)throw new Error(y?.error||y?.message||`上传失败:${p}`);t.push(y.data)}return t}async function B(a){const e=await G();d.value=e||[];const t=d.value.find(p=>p.id===c.value);if(t){c.value=t.id;return}const l=d.value.find(p=>p.isDefault);if(l){c.value=l.id;return}c.value=d.value[0]?.id||""}async function D(a,e){v.value=a,g.value="",f.value=await I(a),r.success(e)}async function $(){const a=F();if(!a?.select_brand_xlsx_files){r.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const e=await a.select_brand_xlsx_files();if(!e?.length)return;await D(e,`已选择 ${e.length} 个待转换文件`)}catch(e){r.error(e instanceof Error?e.message:"选择失败")}}async function N(){const a=F();if(!a?.select_brand_folder){r.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const e=await a.select_brand_folder();if(!e)return;g.value=e.split(/[/\\]/).filter(Boolean).pop()||"";const t=await ee(e);if(t.success&&t.items?.length){v.value=t.items.map(l=>l.relativePath),f.value=await I(t.items),r.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`);return}r.warning(t.error||"该文件夹下没有 xlsx 文件")}catch(e){r.error(e instanceof Error?e.message:"选择失败")}}async function R(){if(!f.value.length){r.warning("请先选择待转换 Excel 文件或文件夹");return}if(!c.value){r.warning("请先选择模板");return}try{m.value=!0;const a=await J({files:f.value.map(e=>({fileKey:e.fileKey,originalFilename:e.originalFilename,relativePath:e.relativePath})),templateId:c.value,archiveName:f.value.some(e=>!!e.relativePath)&&g.value?g.value:void 0});h.value=a,b.value=a.items||[],await C(),r.success("格式转换完成")}catch(a){r.error(a instanceof Error?a.message:"格式转换失败")}finally{m.value=!1}}async function C(){try{const a=await L();b.value=a.items||[],h.value={total:a.items?.length||0,successCount:a.items?.filter(e=>e.success).length||0,failedCount:a.items?.filter(e=>!e.success).length||0,items:a.items||[]}}catch{}}async function S(a){try{await O(a),await C(),r.success("已删除")}catch(e){r.error(e instanceof Error?e.message:"删除失败")}}async function U(a){const e=a.downloadUrl||(a.resultId?W(a.resultId):"");if(!e){r.warning("当前结果没有下载地址");return}const t=a.outputFilename||`${new Date().toISOString().slice(0,10).replace(/-/g,"")}.txt`,l=await Q(e,t,a.resultId?`convert:${a.resultId}`:void 0);l.success?r.success(`已保存:${l.path||t}`):l.error&&l.error!=="用户取消"&&r.error(l.error)}return H(()=>{B().catch(()=>{}),C().catch(()=>{})}),(a,e)=>(n(),o("div",se,[z(K,{active:"convert"}),s("div",te,[s("aside",ae,[e[5]||(e[5]=s("div",{class:"section-title"},"选择文件",-1)),s("div",le,[e[1]||(e[1]=s("div",{class:"hint"},"选择需要转换的 Excel 文件或文件夹,将按所选模板生成 txt 文件。",-1)),s("div",{class:"btns"},[s("button",{type:"button",class:"opt-btn",onClick:$},"选择 Excel 文件"),s("button",{type:"button",class:"opt-btn",onClick:N},"选择文件夹")]),s("div",ne,[v.value.length?(n(),o(w,{key:0},[(n(!0),o(w,null,x(k.value,t=>(n(),o("span",{key:t},i(t),1))),128)),v.value.length>k.value.length?(n(),o("span",oe," 还有 "+i(v.value.length-k.value.length)+" 个文件未展开显示 ",1)):_("",!0)],64)):(n(),o("span",re,"暂未选择待转换文件"))])]),e[6]||(e[6]=s("div",{class:"section-title"},"模板选择",-1)),s("div",ie,[(n(!0),o(w,null,x(d.value,t=>(n(),o("label",{key:t.id,class:P(["radio-item",{active:c.value===t.id}])},[M(s("input",{"onUpdate:modelValue":e[0]||(e[0]=l=>c.value=l),type:"radio",value:t.id,name:"convert-template"},null,8,ce),[[j,c.value]]),s("div",ue,[s("div",null,[s("span",de,[q(i(t.templateName)+" ",1),t.isDefault?(n(),o("span",ve,"默认")):t.builtIn?(n(),o("span",pe,"内置")):(n(),o("span",_e,"自定义"))]),s("div",fe,"输出文件:"+i(t.outputFilename),1)])])],2))),128)),d.value.length?_("",!0):(n(),o("div",me,"暂无可用模板"))]),e[7]||(e[7]=s("div",{class:"section-title"},"转换说明",-1)),s("div",he,[s("label",ye,[e[3]||(e[3]=s("input",{type:"checkbox",checked:"",disabled:""},null,-1)),s("div",null,[e[2]||(e[2]=s("span",{class:"label"},"按当前模板输出",-1)),s("div",ge,"当前模板:"+i(T.value?.templateName||"未加载模板"),1)])]),e[4]||(e[4]=s("label",{class:"radio-item active"},[s("input",{type:"checkbox",checked:"",disabled:""}),s("div",null,[s("span",{class:"label"},"SKU 使用雪花ID-序号"),s("div",{class:"desc"},"例如 1773816146796-1")])],-1))]),s("div",be,[s("button",{type:"button",class:"btn-run",disabled:m.value,onClick:R},i(m.value?"转换中...":"开始转换"),9,we),s("span",ke,i(m.value?"正在生成并上传结果,请稍候…":"选择文件后即可执行格式转换,结果会显示在右侧供下载"),1)])]),s("section",Ce,[e[12]||(e[12]=s("div",{class:"panel-header"},"转换结果",-1)),s("div",xe,[s("div",Fe,[s("div",Ie,[e[8]||(e[8]=s("span",{class:"summary-label"},"已处理文件",-1)),s("strong",null,i(h.value.total),1)]),s("div",Pe,[e[9]||(e[9]=s("span",{class:"summary-label"},"成功结果",-1)),s("strong",null,i(h.value.successCount),1)]),s("div",Ee,[e[10]||(e[10]=s("span",{class:"summary-label"},"失败文件",-1)),s("strong",null,i(h.value.failedCount),1)])]),s("div",Te,[e[11]||(e[11]=s("div",{class:"result-list-header"},[s("span",null,"生成的结果压缩包列表")],-1)),b.value.length===0?(n(),o("div",Be," 暂无转换结果,完成格式转换后会在这里展示结果压缩包 ")):(n(),o("ul",De,[(n(!0),o(w,null,x(b.value,t=>(n(),o("li",{key:`${t.resultId||t.outputFilename||t.sourceFilename}`,class:"task-item"},[s("div",$e,[s("span",{class:"id",title:t.sourceFilename},i(t.sourceFilename||"-"),9,Ne),t.outputFilename?(n(),o("div",Re,"压缩包文件:"+i(t.outputFilename),1)):_("",!0),t.error?(n(),o("div",Se,"错误信息:"+i(t.error),1)):_("",!0)]),s("div",Ue,[s("span",{class:P(["status",t.success?"success":"failed"])},i(t.success?"已完成":"失败"),3),t.success&&(t.downloadUrl||t.resultId)?(n(),o("button",{key:0,type:"button",class:"download",onClick:l=>U(t)}," 下载压缩包 ",8,Ve)):_("",!0),t.resultId?(n(),o("button",{key:1,type:"button",class:"btn-delete",onClick:l=>S(t.resultId)}," 删除 ",8,Ae)):_("",!0)])]))),128))]))])])])])]))}}),ze=X(He,[["__scopeId","data-v-64f58715"]]);Y(ze).use(Z).mount("#app"); diff --git a/app/assets/dedupe.js b/app/assets/dedupe.js index 32bbca7..dc39b29 100644 --- a/app/assets/dedupe.js +++ b/app/assets/dedupe.js @@ -1 +1 @@ -import{d as W,o as z,a as n,c as o,b as q,B as J,e as s,F as C,r as E,t as i,f as b,n as I,w as F,v as P,g as u,h as L,i as B,E as r,j as O,k as G,l as Q,m as X,s as Y,p as Z,_ as ee,q as se,u as te}from"./java-modules-DzYrjxib.js";import{e as le}from"./brand-jr47vQUd.js";const ae={class:"page-shell module-page"},ne={class:"main-content"},oe={class:"left-panel"},re={class:"upload-zone"},ie={class:"selected-files clean-placeholder"},ue={key:0,class:"more-line"},ce={key:1},de={class:"option-group column-option-group"},ve={class:"column-toolbar"},pe={class:"column-count"},fe={key:0,class:"column-grid"},_e=["value"],he={key:1,class:"empty-column-state"},me={class:"option-group"},ge={class:"run-row"},ye=["disabled"],be={class:"loading-msg"},we={class:"right-panel"},ke={class:"task-list-wrap"},Ce={class:"clean-result-summary"},Ie={class:"summary-card"},xe={class:"summary-card"},De={class:"summary-card"},Ee={class:"result-list-wrap"},Fe={key:0,class:"empty-tasks"},Pe={key:1,class:"task-list clean-result-list"},Be={class:"left"},Se=["title"],Ue={key:0,class:"files"},$e={key:1,class:"files"},Ne={class:"task-right"},Ae=["onClick"],He=["onClick"],Ke=W({__name:"BrandDedupeTab",setup(Ve){const p=u([]),c=u([]),f=u([]),w=u(""),d=u([]),S=u(!1),_=u(!0),h=u(!0),m=u(!1),k=u([]),g=u({total:0,successCount:0,failedCount:0,items:[]}),x=L(()=>f.value.slice(0,8));function N(){c.value=[...p.value]}function A(){c.value=[]}async function U(l){const e=B();if(!e?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const a of l){const v=typeof a=="string"?a:a.absolutePath,j=typeof a=="string"?void 0:a.relativePath,y=await e.upload_file_to_java(v,j);if(!y?.success||!y.data)throw new Error(y?.error||y?.message||`上传失败:${v}`);t.push(y.data)}return t}async function $(l){const e=await Z(l);if(!e.headers?.length){r.error("读取 Excel 表头失败"),p.value=[],c.value=[];return}const t=["id","ASIN","国家","价格","卖家名称"],a=[...t.filter(v=>e.headers?.includes(v)),...(e.headers||[]).filter(v=>!t.includes(v))];p.value=a,c.value=t.filter(v=>a.includes(v))}async function H(l,e){f.value=l,w.value="",d.value=await U(l),d.value.length>0&&await $(d.value[0].fileKey),r.success(e)}async function K(){const l=B();if(!l?.select_brand_xlsx_files){r.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const e=await l.select_brand_xlsx_files();if(!e?.length)return;await H(e,`已选择 ${e.length} 个待清洗文件`)}catch(e){r.error(e instanceof Error?e.message:"选择失败")}}async function R(){const l=B();if(!l?.select_brand_folder){r.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const e=await l.select_brand_folder();if(!e)return;w.value=e.split(/[/\\]/).filter(Boolean).pop()||"";const t=await le(e);if(t.success&&t.items?.length){f.value=t.items.map(a=>a.relativePath),d.value=await U(t.items),d.value.length>0&&await $(d.value[0].fileKey),r.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`);return}r.warning(t.error||"该文件夹下没有 xlsx 文件")}catch(e){r.error(e instanceof Error?e.message:"选择失败")}}async function V(){if(!d.value.length){r.warning("请先选择待清洗 Excel 文件或文件夹");return}if(!c.value.length){r.warning("请至少选择一列保留列");return}if(!S.value&&!_.value&&!h.value){r.warning("请至少选择一种 ID 保留规则");return}try{m.value=!0;const l=await O({files:d.value.map(e=>({fileKey:e.fileKey,originalFilename:e.originalFilename,relativePath:e.relativePath})),selectedColumns:c.value,keepIntegerIds:S.value,keepUnderscoreIds:_.value,keepIntegerMainIdsWhenNoSubIds:h.value,archiveName:d.value.some(e=>!!e.relativePath)&&w.value?w.value:void 0});g.value=l,k.value=l.items||[],await D(),r.success("数据去重完成")}catch(l){r.error(l instanceof Error?l.message:"去重失败")}finally{m.value=!1}}async function D(){try{const l=await G();k.value=l.items||[],g.value={total:l.items?.length||0,successCount:l.items?.filter(e=>e.success).length||0,failedCount:l.items?.filter(e=>!e.success).length||0,items:l.items||[]}}catch{}}async function M(l){try{await Q(l),await D(),r.success("已删除")}catch(e){r.error(e instanceof Error?e.message:"删除失败")}}async function T(l){const e=l.downloadUrl||(l.resultId?X(l.resultId):"");if(!e){r.warning("当前结果没有下载地址");return}const t=l.outputFilename||`${new Date().toISOString().slice(0,10).replace(/-/g,"")}_cleaned.xlsx`,a=await Y(e,t,l.resultId?`dedupe:${l.resultId}`:void 0);a.success?r.success(`已保存:${a.path||t}`):a.error&&a.error!=="用户取消"&&r.error(a.error)}return z(()=>{D().catch(()=>{})}),(l,e)=>(n(),o("div",ae,[q(J,{active:"dedupe"}),s("div",ne,[s("aside",oe,[e[7]||(e[7]=s("div",{class:"section-title"},"选择文件",-1)),s("div",re,[e[3]||(e[3]=s("div",{class:"hint"},"选择需要清洗的 Excel 文件或文件夹,后续将按所选规则输出处理结果。",-1)),s("div",{class:"btns"},[s("button",{type:"button",class:"opt-btn",onClick:K},"选择 Excel 文件"),s("button",{type:"button",class:"opt-btn",onClick:R},"选择文件夹")]),s("div",ie,[f.value.length?(n(),o(C,{key:0},[(n(!0),o(C,null,E(x.value,t=>(n(),o("span",{key:t},i(t),1))),128)),f.value.length>x.value.length?(n(),o("span",ue," 还有 "+i(f.value.length-x.value.length)+" 个文件未展开显示 ",1)):b("",!0)],64)):(n(),o("span",ce,"暂未选择待清洗文件"))])]),e[8]||(e[8]=s("div",{class:"section-title"},"保留列设置",-1)),s("div",de,[s("div",ve,[s("span",pe,"已选择 "+i(c.value.length)+" / "+i(p.value.length)+" 列",1),s("div",{class:"column-actions"},[s("button",{type:"button",class:"opt-btn small",onClick:N},"全选"),s("button",{type:"button",class:"opt-btn small",onClick:A},"清空")])]),p.value.length?(n(),o("div",fe,[(n(!0),o(C,null,E(p.value,t=>(n(),o("label",{key:t,class:I(["column-item",{active:c.value.includes(t)}])},[F(s("input",{"onUpdate:modelValue":e[0]||(e[0]=a=>c.value=a),type:"checkbox",value:t},null,8,_e),[[P,c.value]]),s("span",null,i(t),1)],2))),128))])):(n(),o("div",he,"请选择 Excel 文件后读取表头并填充可保留列")),e[4]||(e[4]=s("div",{class:"desc"},"读取首个 Excel 文件的第一行作为表头,用于动态选择需要保留的列。",-1))]),e[9]||(e[9]=s("div",{class:"section-title"},"ID 保留规则",-1)),s("div",me,[s("label",{class:I(["radio-item",{active:_.value}])},[F(s("input",{"onUpdate:modelValue":e[1]||(e[1]=t=>_.value=t),type:"checkbox"},null,512),[[P,_.value]]),e[5]||(e[5]=s("div",null,[s("span",{class:"label"},"保留子链接"),s("div",{class:"desc"},"例如 1_1、2_3 这种带下划线的子项 ID")],-1))],2),s("label",{class:I(["radio-item",{active:h.value}])},[F(s("input",{"onUpdate:modelValue":e[2]||(e[2]=t=>h.value=t),type:"checkbox"},null,512),[[P,h.value]]),e[6]||(e[6]=s("div",null,[s("span",{class:"label"},"仅剩主链接无子链接"),s("div",{class:"desc"},"当某个主链接只有 13 这类主 ID、没有 13_1 这类对应子 ID 时,自动保留该主 ID")],-1))],2)]),s("div",ge,[s("button",{type:"button",class:"btn-run",disabled:m.value,onClick:V},i(m.value?"清洗中...":"开始清洗"),9,ye),s("span",be,i(m.value?"正在处理文件并上传结果,请稍候…":"选择文件、列和 ID 规则后即可执行清洗,结果会显示在右侧供下载"),1)])]),s("section",we,[e[14]||(e[14]=s("div",{class:"panel-header"},"去重结果",-1)),s("div",ke,[s("div",Ce,[s("div",Ie,[e[10]||(e[10]=s("span",{class:"summary-label"},"已处理文件",-1)),s("strong",null,i(g.value.total),1)]),s("div",xe,[e[11]||(e[11]=s("span",{class:"summary-label"},"成功结果",-1)),s("strong",null,i(g.value.successCount),1)]),s("div",De,[e[12]||(e[12]=s("span",{class:"summary-label"},"失败文件",-1)),s("strong",null,i(g.value.failedCount),1)])]),s("div",Ee,[e[13]||(e[13]=s("div",{class:"result-list-header"},[s("span",null,"处理后的 Excel 列表")],-1)),k.value.length===0?(n(),o("div",Fe," 暂无去重结果,完成数据去重后会在这里展示输出文件 ")):(n(),o("ul",Pe,[(n(!0),o(C,null,E(k.value,t=>(n(),o("li",{key:`${t.resultId||t.outputFilename||t.sourceFilename}`,class:"task-item"},[s("div",Be,[s("span",{class:"id",title:t.sourceFilename},i(t.sourceFilename||"-"),9,Se),t.outputFilename?(n(),o("div",Ue,"输出文件:"+i(t.outputFilename),1)):b("",!0),t.error?(n(),o("div",$e,"错误信息:"+i(t.error),1)):b("",!0)]),s("div",Ne,[s("span",{class:I(["status",t.success?"success":"failed"])},i(t.success?"已完成":"失败"),3),t.success&&(t.downloadUrl||t.resultId)?(n(),o("button",{key:0,type:"button",class:"download",onClick:a=>T(t)}," 下载文件 ",8,Ae)):b("",!0),t.resultId?(n(),o("button",{key:1,type:"button",class:"btn-delete",onClick:a=>M(t.resultId)}," 删除 ",8,He)):b("",!0)])]))),128))]))])])])])]))}}),Re=ee(Ke,[["__scopeId","data-v-b83c7062"]]);se(Re).use(te).mount("#app"); +import{d as W,o as z,a as n,c as o,b as q,B as J,e as s,F as C,r as E,t as i,f as b,n as I,w as F,v as P,g as u,h as L,i as B,E as r,j as O,k as G,l as Q,m as X,s as Y,p as Z,_ as ee,q as se,u as te}from"./java-modules-B8c-YG5x.js";import{e as le}from"./brand-COze15GJ.js";const ae={class:"page-shell module-page"},ne={class:"main-content"},oe={class:"left-panel"},re={class:"upload-zone"},ie={class:"selected-files clean-placeholder"},ue={key:0,class:"more-line"},ce={key:1},de={class:"option-group column-option-group"},ve={class:"column-toolbar"},pe={class:"column-count"},fe={key:0,class:"column-grid"},_e=["value"],he={key:1,class:"empty-column-state"},me={class:"option-group"},ge={class:"run-row"},ye=["disabled"],be={class:"loading-msg"},we={class:"right-panel"},ke={class:"task-list-wrap"},Ce={class:"clean-result-summary"},Ie={class:"summary-card"},xe={class:"summary-card"},De={class:"summary-card"},Ee={class:"result-list-wrap"},Fe={key:0,class:"empty-tasks"},Pe={key:1,class:"task-list clean-result-list"},Be={class:"left"},Se=["title"],Ue={key:0,class:"files"},$e={key:1,class:"files"},Ne={class:"task-right"},Ae=["onClick"],He=["onClick"],Ke=W({__name:"BrandDedupeTab",setup(Ve){const p=u([]),c=u([]),f=u([]),w=u(""),d=u([]),S=u(!1),_=u(!0),h=u(!0),m=u(!1),k=u([]),g=u({total:0,successCount:0,failedCount:0,items:[]}),x=L(()=>f.value.slice(0,8));function N(){c.value=[...p.value]}function A(){c.value=[]}async function U(l){const e=B();if(!e?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const a of l){const v=typeof a=="string"?a:a.absolutePath,j=typeof a=="string"?void 0:a.relativePath,y=await e.upload_file_to_java(v,j);if(!y?.success||!y.data)throw new Error(y?.error||y?.message||`上传失败:${v}`);t.push(y.data)}return t}async function $(l){const e=await Z(l);if(!e.headers?.length){r.error("读取 Excel 表头失败"),p.value=[],c.value=[];return}const t=["id","ASIN","国家","价格","卖家名称"],a=[...t.filter(v=>e.headers?.includes(v)),...(e.headers||[]).filter(v=>!t.includes(v))];p.value=a,c.value=t.filter(v=>a.includes(v))}async function H(l,e){f.value=l,w.value="",d.value=await U(l),d.value.length>0&&await $(d.value[0].fileKey),r.success(e)}async function K(){const l=B();if(!l?.select_brand_xlsx_files){r.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const e=await l.select_brand_xlsx_files();if(!e?.length)return;await H(e,`已选择 ${e.length} 个待清洗文件`)}catch(e){r.error(e instanceof Error?e.message:"选择失败")}}async function R(){const l=B();if(!l?.select_brand_folder){r.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const e=await l.select_brand_folder();if(!e)return;w.value=e.split(/[/\\]/).filter(Boolean).pop()||"";const t=await le(e);if(t.success&&t.items?.length){f.value=t.items.map(a=>a.relativePath),d.value=await U(t.items),d.value.length>0&&await $(d.value[0].fileKey),r.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`);return}r.warning(t.error||"该文件夹下没有 xlsx 文件")}catch(e){r.error(e instanceof Error?e.message:"选择失败")}}async function V(){if(!d.value.length){r.warning("请先选择待清洗 Excel 文件或文件夹");return}if(!c.value.length){r.warning("请至少选择一列保留列");return}if(!S.value&&!_.value&&!h.value){r.warning("请至少选择一种 ID 保留规则");return}try{m.value=!0;const l=await O({files:d.value.map(e=>({fileKey:e.fileKey,originalFilename:e.originalFilename,relativePath:e.relativePath})),selectedColumns:c.value,keepIntegerIds:S.value,keepUnderscoreIds:_.value,keepIntegerMainIdsWhenNoSubIds:h.value,archiveName:d.value.some(e=>!!e.relativePath)&&w.value?w.value:void 0});g.value=l,k.value=l.items||[],await D(),r.success("数据去重完成")}catch(l){r.error(l instanceof Error?l.message:"去重失败")}finally{m.value=!1}}async function D(){try{const l=await G();k.value=l.items||[],g.value={total:l.items?.length||0,successCount:l.items?.filter(e=>e.success).length||0,failedCount:l.items?.filter(e=>!e.success).length||0,items:l.items||[]}}catch{}}async function M(l){try{await Q(l),await D(),r.success("已删除")}catch(e){r.error(e instanceof Error?e.message:"删除失败")}}async function T(l){const e=l.downloadUrl||(l.resultId?X(l.resultId):"");if(!e){r.warning("当前结果没有下载地址");return}const t=l.outputFilename||`${new Date().toISOString().slice(0,10).replace(/-/g,"")}_cleaned.xlsx`,a=await Y(e,t,l.resultId?`dedupe:${l.resultId}`:void 0);a.success?r.success(`已保存:${a.path||t}`):a.error&&a.error!=="用户取消"&&r.error(a.error)}return z(()=>{D().catch(()=>{})}),(l,e)=>(n(),o("div",ae,[q(J,{active:"dedupe"}),s("div",ne,[s("aside",oe,[e[7]||(e[7]=s("div",{class:"section-title"},"选择文件",-1)),s("div",re,[e[3]||(e[3]=s("div",{class:"hint"},"选择需要清洗的 Excel 文件或文件夹,后续将按所选规则输出处理结果。",-1)),s("div",{class:"btns"},[s("button",{type:"button",class:"opt-btn",onClick:K},"选择 Excel 文件"),s("button",{type:"button",class:"opt-btn",onClick:R},"选择文件夹")]),s("div",ie,[f.value.length?(n(),o(C,{key:0},[(n(!0),o(C,null,E(x.value,t=>(n(),o("span",{key:t},i(t),1))),128)),f.value.length>x.value.length?(n(),o("span",ue," 还有 "+i(f.value.length-x.value.length)+" 个文件未展开显示 ",1)):b("",!0)],64)):(n(),o("span",ce,"暂未选择待清洗文件"))])]),e[8]||(e[8]=s("div",{class:"section-title"},"保留列设置",-1)),s("div",de,[s("div",ve,[s("span",pe,"已选择 "+i(c.value.length)+" / "+i(p.value.length)+" 列",1),s("div",{class:"column-actions"},[s("button",{type:"button",class:"opt-btn small",onClick:N},"全选"),s("button",{type:"button",class:"opt-btn small",onClick:A},"清空")])]),p.value.length?(n(),o("div",fe,[(n(!0),o(C,null,E(p.value,t=>(n(),o("label",{key:t,class:I(["column-item",{active:c.value.includes(t)}])},[F(s("input",{"onUpdate:modelValue":e[0]||(e[0]=a=>c.value=a),type:"checkbox",value:t},null,8,_e),[[P,c.value]]),s("span",null,i(t),1)],2))),128))])):(n(),o("div",he,"请选择 Excel 文件后读取表头并填充可保留列")),e[4]||(e[4]=s("div",{class:"desc"},"读取首个 Excel 文件的第一行作为表头,用于动态选择需要保留的列。",-1))]),e[9]||(e[9]=s("div",{class:"section-title"},"ID 保留规则",-1)),s("div",me,[s("label",{class:I(["radio-item",{active:_.value}])},[F(s("input",{"onUpdate:modelValue":e[1]||(e[1]=t=>_.value=t),type:"checkbox"},null,512),[[P,_.value]]),e[5]||(e[5]=s("div",null,[s("span",{class:"label"},"保留子链接"),s("div",{class:"desc"},"例如 1_1、2_3 这种带下划线的子项 ID")],-1))],2),s("label",{class:I(["radio-item",{active:h.value}])},[F(s("input",{"onUpdate:modelValue":e[2]||(e[2]=t=>h.value=t),type:"checkbox"},null,512),[[P,h.value]]),e[6]||(e[6]=s("div",null,[s("span",{class:"label"},"仅剩主链接无子链接"),s("div",{class:"desc"},"当某个主链接只有 13 这类主 ID、没有 13_1 这类对应子 ID 时,自动保留该主 ID")],-1))],2)]),s("div",ge,[s("button",{type:"button",class:"btn-run",disabled:m.value,onClick:V},i(m.value?"清洗中...":"开始清洗"),9,ye),s("span",be,i(m.value?"正在处理文件并上传结果,请稍候…":"选择文件、列和 ID 规则后即可执行清洗,结果会显示在右侧供下载"),1)])]),s("section",we,[e[14]||(e[14]=s("div",{class:"panel-header"},"去重结果",-1)),s("div",ke,[s("div",Ce,[s("div",Ie,[e[10]||(e[10]=s("span",{class:"summary-label"},"已处理文件",-1)),s("strong",null,i(g.value.total),1)]),s("div",xe,[e[11]||(e[11]=s("span",{class:"summary-label"},"成功结果",-1)),s("strong",null,i(g.value.successCount),1)]),s("div",De,[e[12]||(e[12]=s("span",{class:"summary-label"},"失败文件",-1)),s("strong",null,i(g.value.failedCount),1)])]),s("div",Ee,[e[13]||(e[13]=s("div",{class:"result-list-header"},[s("span",null,"处理后的 Excel 列表")],-1)),k.value.length===0?(n(),o("div",Fe," 暂无去重结果,完成数据去重后会在这里展示输出文件 ")):(n(),o("ul",Pe,[(n(!0),o(C,null,E(k.value,t=>(n(),o("li",{key:`${t.resultId||t.outputFilename||t.sourceFilename}`,class:"task-item"},[s("div",Be,[s("span",{class:"id",title:t.sourceFilename},i(t.sourceFilename||"-"),9,Se),t.outputFilename?(n(),o("div",Ue,"输出文件:"+i(t.outputFilename),1)):b("",!0),t.error?(n(),o("div",$e,"错误信息:"+i(t.error),1)):b("",!0)]),s("div",Ne,[s("span",{class:I(["status",t.success?"success":"failed"])},i(t.success?"已完成":"失败"),3),t.success&&(t.downloadUrl||t.resultId)?(n(),o("button",{key:0,type:"button",class:"download",onClick:a=>T(t)}," 下载文件 ",8,Ae)):b("",!0),t.resultId?(n(),o("button",{key:1,type:"button",class:"btn-delete",onClick:a=>M(t.resultId)}," 删除 ",8,He)):b("",!0)])]))),128))]))])])])])]))}}),Re=ee(Ke,[["__scopeId","data-v-b83c7062"]]);se(Re).use(te).mount("#app"); diff --git a/app/assets/delete-brand.js b/app/assets/delete-brand.js index 99dcbf5..ed1eb6c 100644 --- a/app/assets/delete-brand.js +++ b/app/assets/delete-brand.js @@ -1 +1 @@ -import{d as ns,o as ls,M as rs,a as d,c as f,b as os,B as us,e as r,F as V,r as ye,t as v,f as h,N as is,O as qe,n as Oe,g as y,h as z,P as cs,i as ne,E as p,Q as ds,R as fs,S as vs,s as hs,T as ps,U as _s,V as ys,_ as gs,q as ms,u as ks}from"./java-modules-DzYrjxib.js";import{e as ws}from"./brand-jr47vQUd.js";import{c as Is}from"./categorized-timers-JPA-olTr.js";const bs={class:"page-shell module-page"},Ss={class:"main-content"},Ts={class:"left-panel"},Cs={class:"upload-zone"},Rs={class:"selected-files clean-placeholder split-selected-files"},Ns={key:0,class:"more-line"},Es={key:1},Fs={class:"run-row"},Ps=["disabled"],xs=["disabled"],$s={class:"loading-msg"},As={key:0,class:"queue-debug-card"},Ds={key:0,class:"queue-debug-line"},Ms={key:1,class:"queue-debug-payload"},Bs={class:"right-panel"},Us={class:"task-list-wrap"},Ls={class:"clean-result-summary"},qs={class:"summary-card"},Os={class:"summary-card"},Ks={class:"summary-card"},Gs={class:"result-list-wrap"},Hs={key:0,class:"empty-tasks"},Js={key:0,class:"result-subsection"},js={class:"task-list clean-result-list"},Vs={class:"left split-result-main"},zs=["title"],Qs={class:"files"},Xs={class:"files"},Ws={key:0,class:"files"},Ys={key:1,class:"files"},Zs={key:2,class:"files"},et={key:3,class:"time"},st={key:4,class:"delete-brand-progress-block"},tt={class:"delete-brand-progress-header"},at={class:"delete-brand-progress-bar"},nt={class:"files delete-brand-progress"},lt={key:5,class:"files split-entry-list delete-brand-preview"},rt={key:6,class:"files"},ot={class:"task-right split-result-actions"},ut=["onClick"],it=["onClick"],ct={key:1,class:"result-subsection"},dt={class:"task-list clean-result-list"},ft={class:"left split-result-main"},vt=["title"],ht={class:"files"},pt={class:"files"},_t={key:0,class:"files"},yt={key:1,class:"files"},gt={key:2,class:"time"},mt={key:3,class:"delete-brand-progress-block"},kt={class:"delete-brand-progress-header"},wt={class:"delete-brand-progress-bar"},It={class:"files delete-brand-progress"},bt={key:4,class:"files split-entry-list delete-brand-preview"},St={key:5,class:"files"},Tt={class:"task-right split-result-actions"},Ct=["onClick"],Rt=["onClick"],Nt=ns({__name:"BrandDeleteBrandTab",setup(Ft){function D(){return`delete-brand:current-tasks:${typeof window<"u"&&window.localStorage.getItem("uid")||"0"}`}const M=y([]),Q=y([]),O=y(!1),ge=y([]),i=y([]),K=y([]),X=y({total:0,successCount:0,failedCount:0,items:[]}),b=y(""),S=y(""),m=y({}),T=y(null),le=y(!1),W=y(!1),R=y(!1),B=y(""),Y=y(!1),G=y(null),re=y(!1);let U=!1;const L=Is("delete-brand"),oe=z(()=>M.value.slice(0,10)),N=z(()=>{const e=[...i.value].sort((t,a)=>(a.createdAt||0)-(t.createdAt||0)),s=[];return e.forEach(t=>{s.push(...t.items)}),s});function Ke(){try{const e=typeof window<"u"?window.localStorage.getItem(D()):null;if(e){if(i.value=JSON.parse(e),i.value.length>0){const s=i.value[i.value.length-1];b.value=s.queuePushResult||"",S.value=s.queuePayloadText||""}}else i.value=[]}catch{i.value=[]}}function ue(e,s,t,a){if(!s?.length)return;const l=i.value.findIndex(c=>c.taskId===e),o=l>=0?i.value[l]:null,n=s.map(c=>{const _=o?.items.find(as=>q(as,c)),k=Array.isArray(c.countries)?c.countries:void 0,g=Array.isArray(_?.countries)?_?.countries:void 0,w=k&&k.length>0?k:g&&g.length>0?g:k??g,I=Array.isArray(c.previewRows)?c.previewRows:void 0,C=Array.isArray(_?.previewRows)?_?.previewRows:void 0,_e=I&&I.length>0?I:C&&C.length>0?C:I??C;return{...c,countries:w,previewRows:_e,_pushed:_?._pushed??c._pushed??!1,_completed:_?._completed??c._completed??!1}}),u={taskId:e,items:n,createdAt:o?.createdAt||Date.now(),queuePushResult:t??o?.queuePushResult,queuePayloadText:a??o?.queuePayloadText};l>=0?i.value[l]=u:i.value.push(u),typeof window<"u"&&window.localStorage.setItem(D(),JSON.stringify(i.value))}function me(e){const s=i.value.length;i.value=i.value.filter(t=>t.taskId!==e),i.value.length!==s&&typeof window<"u"&&window.localStorage.setItem(D(),JSON.stringify(i.value))}function ke(e){return e==="SUCCESS"||e==="FAILED"||e==="COMPLETED"}function Ge(e){if(!e?.length)return!1;const s=new Set;if(e.forEach(a=>{a.taskId&&ke(a.taskStatus)&&s.add(a.taskId)}),!s.size)return!1;const t=i.value.length;return i.value=i.value.filter(a=>!s.has(a.taskId)),i.value.length!==t?(ie(),!0):!1}const Z=z(()=>K.value.filter(e=>!N.value.some(s=>q(s,e)))),He=z(()=>N.value.length>0||Z.value.length>0),Je=z(()=>N.value.filter(e=>Me(e)&&E(e)==="未入队"));function ie(){typeof window<"u"&&(i.value.length===0?window.localStorage.removeItem(D()):window.localStorage.setItem(D(),JSON.stringify(i.value)))}function P(e){return e?(i.value.find(t=>t.taskId===e)?.items.length||0)>1:!1}function ce(e){return e&&i.value.find(s=>s.taskId===e)||null}function q(e,s){return!e||!s?!1:e.resultId!=null&&s.resultId!=null?e.resultId===s.resultId:e.fileKey&&s.fileKey?e.fileKey===s.fileKey:e.sourceFilename===s.sourceFilename}function x(e,s){const t=ce(e);return t&&t.items.find(a=>q(a,s))||null}function we(e){if(!e)return!1;const s=ce(e);if(!s)return!1;let t=!1;const a=m.value[e]?.line_progress?.info,l=P(e);if(a?.file_name&&a.current_line!=null&&a.total_lines!=null&&a.total_lines>0&&a.current_line>=a.total_lines){const o=s.items.find(n=>n.sourceFilename===a.file_name);o&&!o._completed&&(o._completed=!0,t=!0)}if(!l){const o=m.value[e]?.task?.status;if((o==="SUCCESS"||o==="FAILED")&&s.items.length===1){const n=s.items[0];n&&!n._completed&&(n._completed=!0,t=!0)}}return t&&ie(),t}function Ie(e){return e&&m.value[e]?.task?.status||""}function ee(e){if(e.error)return e.error;if(e.matchStatus&&e.matchStatus!=="MATCHED")return e.matchMessage||"";const s=e.taskId;return s&&m.value[s]?.task?.errorMessage||""}function be(e){const s=e.taskId;if(!s)return!1;const t=m.value[s]?.line_progress,a=Ie(s),l=P(s),o=E(e);if(l){const n=x(s,e),u=j(e)===B.value,c=!!(t?.has_progress&&t?.info?.file_name===e.sourceFilename);return u||c||n?._pushed||(a==="RUNNING"||a==="PENDING"||!a)&&n?._completed?!0:{success:!1,retryable:!0}}return o==="本文件解析完毕"||o==="已被全局判定为终态"?!1:t?.has_progress||t?.info?!0:o==="已入队"||o==="处理中"}function Se(e){return e.map(s=>A(s)?{...s,matched:!0,_pushed:!1,_completed:!1}:{...s,matched:!1,openStoreUrl:void 0,error:s.error||void 0,_pushed:!1,_completed:!1})}function Te(e){return e.matchStatus==="INDEX_STALE"&&A(e)?`已匹配 ${e.shopId||""}(索引过期,可继续推送)`.trim():e.matchStatus==="MATCHED"||e.matched?`已匹配 ${e.shopId||""}`.trim():e.matchMessage?e.matchMessage:e.matchStatus==="CONFLICT"?"存在多个同名店铺,请人工确认":e.matchStatus==="PENDING"?"店铺索引暂未就绪":e.matchStatus?e.matchStatus:e.matched?`已匹配 ${e.shopId||""}`.trim():"待匹配"}function je(){ge.value=[...N.value,...Z.value]}function $(){je(),Ve(ge.value)}function Ve(e){X.value={total:e.length,successCount:e.filter(s=>s.success).length,failedCount:e.filter(s=>!s.success).length,items:e}}function de(e){const s=e.taskId;return s&&(m.value[s]?.fileProgress||[]).find(l=>l.fileKey&&e.fileKey?l.fileKey===e.fileKey:l.sourceFilename&&e.sourceFilename?l.sourceFilename===e.sourceFilename:!1)||null}function Ce(e){const s=e.taskId;if(!s)return"";const t=m.value[s],a=t?.line_progress?.info,l=de(e);if(P(s)){const u=x(s,e),c=t?.task?.status,_=!!(a?.file_name&&a.file_name===e.sourceFilename);let k=u?._completed?"COMPLETED":(u?._pushed,"PENDING"),g=0,w=Math.max(0,e.totalRows??l?.totalRows??0);c==="SUCCESS"||c==="FAILED"&&u?._completed?(k="COMPLETED",g=w):_?(k="RUNNING",g=Math.max(0,Math.min(w||Number.MAX_SAFE_INTEGER,a?.current_line??0)),!w&&a?.total_lines&&a.total_lines>0&&(w=a.total_lines)):u?._completed?(k="COMPLETED",g=w):u?._pushed&&(k="PENDING",g=0);const I=[];if(I.push(`文件状态:${k}`),I.push(`文件进度:${g}/${w}`),a?.finished_files!=null){const C=a.file_total&&a.file_total>0?`/${a.file_total}`:"";I.push(`已完成文件:${a.finished_files}${C}`)}return a?.phase&&I.push(`阶段:${a.phase}`),I.join("|")}if(l){const u=[],c=l.processedRows??0,_=l.totalRows??0;if(l.status&&u.push(`文件状态:${l.status}`),u.push(`文件进度:${c}/${_}`),a?.finished_files!=null){const k=a.file_total&&a.file_total>0?`/${a.file_total}`:"";u.push(`已完成文件:${a.finished_files}${k}`)}return a?.phase&&u.push(`阶段:${a.phase}`),u.join("|")}if(!t?.line_progress?.has_progress||!a){const u=t?.task?.status;return u?`任务状态:${u}`:""}const n=[];if(a.phase&&n.push(`阶段:${a.phase}`),a.file_index&&a.file_total&&n.push(`文件:${a.file_index}/${a.file_total}`),a.file_name&&n.push(`当前文件:${a.file_name}`),a.current_line!=null&&a.total_lines!=null&&n.push(`${P(s)?"当前文件进度":"进度"}:${a.current_line}/${a.total_lines}`),a.current_country&&n.push(`国家:${a.current_country}`),a.current_asin&&n.push(`ASIN:${a.current_asin}`),a.finished_files!=null){const u=a.file_total&&a.file_total>0?`/${a.file_total}`:"";n.push(`已完成文件:${a.finished_files}${u}`)}return n.join("|")}function se(e){const s=e.taskId;if(!s)return 0;const t=m.value[s]?.line_progress?.info;if(P(s)){const n=x(s,e);if(m.value[s]?.task?.status==="SUCCESS"||n?._completed)return 100;const c=Math.max(0,e.totalRows??de(e)?.totalRows??0);if(!!(t?.file_name&&t.file_name===e.sourceFilename)){if(t?.current_line!=null&&t?.total_lines&&t.total_lines>0)return Math.max(0,Math.min(100,Math.round(t.current_line/t.total_lines*100)));if(t?.current_line!=null&&c>0)return Math.max(0,Math.min(100,Math.round(t.current_line/c*100)))}return 0}const l=de(e);return l?Math.max(0,Math.min(100,l.percent??0)):t?t.current_line!=null&&t.total_lines&&t.total_lines>0?Math.max(0,Math.min(100,Math.round(t.current_line/t.total_lines*100))):t.finished_files!=null&&t.file_total&&t.file_total>0?Math.max(0,Math.min(100,Math.round(t.finished_files/t.file_total*100))):m.value[s]?.task?.status==="SUCCESS"?100:0:0}function Re(e){const s=m.value[e]?.task?.status;return ke(s)}function H(){const e=new Set;return i.value.forEach(s=>{s.items.some(t=>t._pushed)&&e.add(s.taskId)}),Array.from(e)}function E(e){const s=e.taskId;if(!s||!ce(s))return"";const a=x(s,e),l=Ie(s),o=m.value[s]?.line_progress,n=P(s);if(!n&&(l==="SUCCESS"||l==="FAILED"||e.taskStatus==="SUCCESS"||e.taskStatus==="FAILED"))return"已被全局判定为终态";if(te(e)||te(a)||a?._completed)return"本文件解析完毕";if(l==="RUNNING"&&o?.has_progress&&o?.info?.file_name===e.sourceFilename)return"处理中";if(n&&!a?._pushed&&!a?._completed)return"未入队";if(n&&l==="SUCCESS")return"本文件解析完毕";if(!n){const u=m.value[s];if(u?.items&&u.items.find(_=>q(_,e))&&l==="SUCCESS")return"本文件解析完毕"}return a?._pushed?"已入队":"未入队"}function Ne(e){return!!(e.downloadUrl||e.fileReady)}function te(e){if(!e)return!1;const s=String(e.fileStatus||"").toUpperCase();return!!(e.fileReady||e.downloadUrl||s==="SUCCESS"||s==="COMPLETED")}function F(e,s){return e??s}function ze(e){const s=e?.task?.id;if(!s)return!1;const t=i.value.find(n=>n.taskId===s);if(!t)return{success:!1,retryable:!1};const a=e?.items||[];let l=!1;const o=t.items.map(n=>{const u=a.find(_e=>q(_e,n));if(!u)return n;const c=Array.isArray(u.countries)?u.countries:void 0,_=Array.isArray(n.countries)?n.countries:void 0,k=c&&c.length>0?c:_&&_.length>0?_:c??_,g=Array.isArray(u.previewRows)?u.previewRows:void 0,w=Array.isArray(n.previewRows)?n.previewRows:void 0,I=g&&g.length>0?g:w&&w.length>0?w:g??w,C={...n,...u,shopName:F(u.shopName,n.shopName),companyName:F(u.companyName,n.companyName),shopId:F(u.shopId,n.shopId),platform:F(u.platform,n.platform),openStoreUrl:F(u.openStoreUrl,n.openStoreUrl),matchStatus:F(u.matchStatus,n.matchStatus),matchMessage:F(u.matchMessage,n.matchMessage),matched:A(n)||A(u),countryCount:F(u.countryCount,n.countryCount),countries:k,previewRows:I,_pushed:n._pushed,_completed:n._completed||te(u)};return JSON.stringify(C)!==JSON.stringify(n)&&(l=!0),C});for(const n of a)o.some(u=>q(u,n))||(o.push({...n,_pushed:!1,_completed:te(n)}),l=!0);return JSON.stringify(o)!==JSON.stringify(t.items)&&(t.items=o,l=!0),l&&ie(),l}async function fe(e){const s=e||H();if(s.length)try{const t=await cs(s);re.value&&R.value&&(b.value="后端已恢复,继续执行当前任务并自动衔接后续任务..."),re.value=!1;let a=!1;for(const l of t.items||[]){const o=l?.task?.id;typeof o=="number"&&o>0&&(m.value[o]=l,ze(l)&&(a=!0),we(o)&&(a=!0))}a&&$()}catch(t){const a=(t instanceof Error?t.message:String(t||"")).toLowerCase();["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(o=>a.includes(o.toLowerCase()))&&R.value&&(re.value=!0,b.value="当前任务运行中,正在等待后端服务恢复...")}}function Qe(){return ys()}function ve(e=!1){if(U)return;if(T.value){if(!e)return;L.clearTimer("task-poll",T.value),T.value=null}const s=async()=>{if(T.value=null,U)return;if(le.value){ve();return}const t=H();if(!t.length)return;le.value=!0;let a=!1,l=!1;try{await fe(t),await Le();for(const o of t)Re(o)&&(me(o),a=!0,l=!0)}finally{le.value=!1}l?await J():a&&$(),!U&&H().length>0&&ve()};e?s():T.value=L.setTimeout("task-poll",s,Qe())}function he(e=!1){T.value&&!e||ve(e)}function ae(e){if(e.fileReady||e.downloadUrl)return{className:"success",text:"已完成"};const s=e.taskId?m.value[e.taskId]?.task?.status:null;return s==="SUCCESS"?{className:"success",text:"已完成"}:s==="FAILED"?{className:"failed",text:"失败"}:s==="RUNNING"?{className:"running",text:"执行中"}:e.taskStatus==="SUCCESS"?{className:"success",text:"已完成"}:e.taskStatus==="FAILED"?{className:"failed",text:"失败"}:e.taskStatus==="RUNNING"?{className:"running",text:"执行中"}:e.success?{className:"success",text:"已完成"}:{className:"failed",text:"失败"}}function Ee(){T.value&&(L.clearTimer("task-poll",T.value),T.value=null),pe()}async function Fe(e){const s=ne();if(!s?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const a of e){const l=typeof a=="string"?a:a.absolutePath,o=typeof a=="string"?void 0:a.relativePath,n=await s.upload_file_to_java(l,o);if(!n?.success||!n.data)throw new Error(n?.error||n?.message||`上传失败:${l}`);t.push(n.data)}return t}async function Xe(){const e=ne();if(!e?.select_brand_xlsx_files){p.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const s=await e.select_brand_xlsx_files();if(!s?.length)return;M.value=s,Q.value=await Fe(s),p.success(`已选择 ${s.length} 个删除品牌文件`)}catch(s){p.error(s instanceof Error?s.message:"选择失败")}}async function We(){const e=ne();if(!e?.select_brand_folder){p.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const s=await e.select_brand_folder();if(!s)return;const t=await ws(s);if(!t.success||!t.items?.length){p.warning(t.error||"该文件夹下没有 xlsx 文件");return}M.value=t.items.map(a=>a.relativePath||a.absolutePath),Q.value=await Fe(t.items),p.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`)}catch(s){p.error(s instanceof Error?s.message:"选择失败")}}async function Ye(){if(!Q.value.length){p.warning("请先选择待处理文件");return}try{O.value=!0;const e=await ds({files:Q.value.map(o=>({fileKey:o.fileKey,originalFilename:o.originalFilename,relativePath:o.relativePath}))}),s=Se(e.items||[]),t=s.some(o=>A(o)),a=s.some(o=>o.matchStatus==="INDEX_STALE"&&o.matched),l=s.some(o=>!A(o));b.value=t?"解析完成,可在左侧点击“推送到 Python 队列”开始串行处理":"解析完成,当前没有可推送的文件",S.value="",s.length&&s[0].taskId&&ue(s[0].taskId,s,b.value,S.value),$(),l?p.warning("部分文件尚未命中可用店铺索引,已保留状态信息,请等待后台刷新后重试。"):a?p.warning("部分文件命中的是过期索引,仍可推送到 Python 队列;后台刷新后会自动重新匹配。"):t?p.success("删除品牌解析完成,请在左侧推送到 Python 队列"):p.warning("当前没有可推送的文件,请先等待店铺索引刷新。"),await J()}catch(e){p.error(e instanceof Error?e.message:"执行失败")}finally{O.value=!1}}async function Pe(e){const s=e.taskId;if(!s){p.warning("未找到任务ID");return}const t=e.resultId?fs(e.resultId):vs(s),a=e.outputFilename||e.sourceFilename||`delete-brand_${s}.xlsx`,l=await hs(t,a,e.resultId?`delete-brand:${e.resultId}`:`delete-brand-task:${s}`);l.success?p.success(`已保存:${l.path||a}`):l.error&&l.error!=="用户取消"&&p.error(l.error)}async function J(){try{const e=await ps();K.value=Se(e.items||[]),Ge(K.value),$(),await fe(),he(!0)}catch(e){const s=(e instanceof Error?e.message:String(e||"")).toLowerCase();["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(a=>s.includes(a.toLowerCase()))||console.error("loadHistory error:",e)}}function xe(e){i.value.forEach(t=>{t.items=t.items.filter(a=>a.resultId!==e)});const s=i.value.length;i.value=i.value.filter(t=>t.items.length>0),i.value.length!==s&&typeof window<"u"&&window.localStorage.setItem(D(),JSON.stringify(i.value)),K.value=K.value.filter(t=>t.resultId!==e),$(),H().length===0&&Ee()}async function $e(e){try{await _s(e),xe(e),await J(),p.success("已删除")}catch(s){const t=s instanceof Error?s.message:"删除失败";if(typeof t=="string"&&t.includes("记录不存在")){xe(e),p.success("已删除");return}p.error(t)}}function Ae(e){const s=e.slice(0,5).map(a=>`${a.country}:${a.asin}${a.status?`(${a.status})`:""}`);return e.length-s.length>0?`${s.join("、")} 等 ${e.length} 条`:s.join("、")}function Pt(e,s){}function pe(){G.value&&(L.clearTimer("auto-retry",G.value),G.value=null)}function Ze(e=3e3){U||(pe(),G.value=L.setTimeout("auto-retry",()=>{G.value=null,U||Le().catch(()=>{})},e))}function es(e){return e.includes("当前店铺正在执行中")}function De(){for(const e of i.value)for(const s of e.items){const t=E(s);if(t==="已入队"||t==="处理中")return!0}return!1}function j(e){return e.resultId!=null?`result:${e.resultId}`:`task:${e.taskId||0}:${e.sourceFilename||""}`}function A(e){return!!(e.matched||e.matchStatus==="MATCHED"||e.matchStatus==="INDEX_STALE"&&e.shopId)}function ss(e){return!!(e.shopName&&Array.isArray(e.countries)&&e.countries.length>0)}function Me(e){return!!(e.taskId&&(A(e)||ss(e)))}function Be(){return N.value.find(e=>!Me(e)||j(e)===B.value||x(e.taskId,e)?._completed?!1:E(e)==="未入队")}async function Ue(e,s){if(s?.auto&&De())return e.taskId,e.sourceFilename,{success:!1,retryable:!0};const t=ne(),a=e.taskId;if(!a)return{success:!1,retryable:!1};const l=i.value.find(c=>c.taskId===a);if(!l)return{success:!1,retryable:!1};if(!t?.enqueue_json)return p.error("当前环境未启用 pywebview enqueue_json(浏览器环境不会推送)"),{success:!1,retryable:!1};const o={type:"delete-brand-run",ts:Date.now(),data:{taskId:a,items:[e]}};S.value=JSON.stringify(o,null,2);const n=await t.enqueue_json(o);let u="";if(n?.success){u=`已推送文件 ${e.sourceFilename},当前队列长度:${n.queue_size??"-"}`;const c=x(a,e);return c&&(c._pushed=!0,c._completed=!1),B.value=j(e),ue(a,l.items,u,S.value),he(!0),b.value=u,{success:!0,retryable:!1}}else{const c=n?.error||"未知错误";if(u=`推送到 Python 队列失败:${c}`,b.value=u,ue(a,l.items,u,S.value),s?.auto&&es(c))return{success:!1,retryable:!0}}return b.value=u,{success:!1,retryable:!1}}async function ts(){const e=Be();if(!e){p.warning("当前没有可推送的文件");return}W.value=!0,R.value=!0,pe();const s=await Ue(e);if(W.value=!1,!s.success){R.value=!1,B.value="";return}p.success("已开始按顺序推送到 Python 队列")}async function Le(){if(!R.value||Y.value){R.value,Y.value;return}if(De())return;const e=B.value;if(e){const t=N.value.find(a=>j(a)===e);if(t){const a=t.taskId,l=P(a);l&&(we(a),E(t),void 0);const o=E(t);if(o==="已入队"||o==="处理中"){t.sourceFilename;return}if(l){const n=x(a,t);if(n&&!n._completed){t.sourceFilename,n._pushed,n._completed;return}}}}const s=Be();if(!s){B.value="",R.value=!1;return}Y.value=!0;try{s.taskId,s.sourceFilename,j(s);const t=await Ue(s,{auto:!0});if(!t.success){if(t.retryable){s.taskId,s.sourceFilename,Ze();return}s.taskId,s.sourceFilename,R.value=!1}}finally{Y.value=!1}}return ls(()=>{Ke();const e=H();e.length>0?fe(e).then(async()=>{let s=!1,t=!1;for(const a of e)Re(a)&&(me(a),s=!0,t=!0);t?await J():s&&$(),he(!0)}):$(),J().catch(()=>{})}),rs(()=>{U=!0,Ee(),L.clearScope()}),(e,s)=>(d(),f("div",bs,[os(us,{active:"delete-brand"}),r("div",Ss,[r("aside",Ts,[s[2]||(s[2]=r("div",{class:"section-title"},"选择文件",-1)),r("div",Cs,[s[0]||(s[0]=r("div",{class:"hint"},"上传删除品牌 Excel;无论是直接上传文件还是上传文件夹批量导入,都会按每个 Excel 文件名作为店铺名。",-1)),r("div",{class:"btns"},[r("button",{type:"button",class:"opt-btn",onClick:Xe},"选择 Excel 文件"),r("button",{type:"button",class:"opt-btn",onClick:We},"选择文件夹")]),r("div",Rs,[M.value.length?(d(),f(V,{key:0},[(d(!0),f(V,null,ye(oe.value,t=>(d(),f("span",{key:t},v(t),1))),128)),M.value.length>oe.value.length?(d(),f("span",Ns," 还有 "+v(M.value.length-oe.value.length)+" 个文件未展开显示 ",1)):h("",!0)],64)):(d(),f("span",Es,"暂未选择删除品牌文件"))])]),s[3]||(s[3]=is('
执行说明
',2)),r("div",Fs,[r("button",{type:"button",class:"btn-run",disabled:O.value,onClick:Ye},v(O.value?"解析中...":"开始解析"),9,Ps),r("button",{type:"button",class:"btn-run btn-queue",disabled:W.value||!Je.value.length,onClick:ts},v(W.value?"推送中...":"推送到 Python 队列"),9,xs),r("span",$s,v(O.value?"正在读取删除品牌数据,请稍候…":"解析后会在右侧展示按国家分组的去重结果"),1)]),b.value||S.value?(d(),f("div",As,[s[1]||(s[1]=r("div",{class:"section-title queue-debug-title"},"Python 队列推送结果",-1)),b.value?(d(),f("div",Ds,v(b.value),1)):h("",!0),S.value?(d(),f("pre",Ms,v(S.value),1)):h("",!0)])):h("",!0)]),r("section",Bs,[s[12]||(s[12]=r("div",{class:"panel-header"},"删除品牌结果",-1)),r("div",Us,[r("div",Ls,[r("div",qs,[s[4]||(s[4]=r("span",{class:"summary-label"},"已处理文件",-1)),r("strong",null,v(X.value.total),1)]),r("div",Os,[s[5]||(s[5]=r("span",{class:"summary-label"},"成功结果",-1)),r("strong",null,v(X.value.successCount),1)]),r("div",Ks,[s[6]||(s[6]=r("span",{class:"summary-label"},"失败文件",-1)),r("strong",null,v(X.value.failedCount),1)])]),r("div",Gs,[s[11]||(s[11]=r("div",{class:"result-list-header"},[r("span",null,"删除品牌结果列表")],-1)),He.value?(d(),f(V,{key:1},[N.value.length?(d(),f("div",Js,[s[8]||(s[8]=r("div",{class:"result-subsection-title"},"当前任务",-1)),r("ul",js,[(d(!0),f(V,null,ye(N.value,t=>(d(),f("li",{key:`current-${t.taskId||t.resultId||t.sourceFilename}`,class:"task-item split-result-item"},[r("div",Vs,[r("span",{class:"id",title:t.sourceFilename},v(t.sourceFilename||"-"),9,zs),r("div",Qs,"店铺名:"+v(t.shopName||"-"),1),r("div",Xs,"匹配结果:"+v(Te(t)),1),t.platform?(d(),f("div",Ws,"平台:"+v(t.platform),1)):h("",!0),E(t)?(d(),f("div",Ys,"队列状态:"+v(E(t)),1)):h("",!0),t.countryCount!==void 0&&t.matched?(d(),f("div",Zs,"国家数:"+v(t.countryCount),1)):h("",!0),t.totalRows!==void 0&&t.matched?(d(),f("div",et,"去重后 "+v(t.totalRows)+" 条 ",1)):h("",!0),be(t)?(d(),f("div",st,[r("div",tt,[s[7]||(s[7]=r("span",null,"任务进度",-1)),r("span",null,v(se(t))+"%",1)]),r("div",at,[r("div",{class:"delete-brand-progress-bar-fill",style:qe({width:`${se(t)}%`})},null,4)]),r("div",nt,v(Ce(t)),1)])):h("",!0),t.previewRows?.length?(d(),f("div",lt,v(Ae(t.previewRows)),1)):h("",!0),ee(t)?(d(),f("div",rt,"错误信息:"+v(ee(t)),1)):h("",!0)]),r("div",ot,[r("span",{class:Oe(["status",ae(t).className])},v(ae(t).text),3),Ne(t)?(d(),f("button",{key:0,type:"button",class:"download",onClick:a=>Pe(t)}," 下载 ",8,ut)):h("",!0),t.resultId?(d(),f("button",{key:1,type:"button",class:"btn-delete",onClick:a=>$e(t.resultId)}," 删除 ",8,it)):h("",!0)])]))),128))])])):h("",!0),Z.value.length?(d(),f("div",ct,[s[10]||(s[10]=r("div",{class:"result-subsection-title"},"历史记录",-1)),r("ul",dt,[(d(!0),f(V,null,ye(Z.value,t=>(d(),f("li",{key:`history-${t.taskId||t.resultId||t.sourceFilename}`,class:"task-item split-result-item"},[r("div",ft,[r("span",{class:"id",title:t.sourceFilename},v(t.sourceFilename||"-"),9,vt),r("div",ht,"店铺名:"+v(t.shopName||"-"),1),r("div",pt,"匹配结果:"+v(Te(t)),1),t.platform?(d(),f("div",_t,"平台:"+v(t.platform),1)):h("",!0),t.countryCount!==void 0&&t.matched?(d(),f("div",yt,"国家数:"+v(t.countryCount),1)):h("",!0),t.totalRows!==void 0&&t.matched?(d(),f("div",gt,"去重后 "+v(t.totalRows)+" 条 ",1)):h("",!0),be(t)?(d(),f("div",mt,[r("div",kt,[s[9]||(s[9]=r("span",null,"任务进度",-1)),r("span",null,v(se(t))+"%",1)]),r("div",wt,[r("div",{class:"delete-brand-progress-bar-fill",style:qe({width:`${se(t)}%`})},null,4)]),r("div",It,v(Ce(t)),1)])):h("",!0),t.previewRows?.length?(d(),f("div",bt,v(Ae(t.previewRows)),1)):h("",!0),ee(t)?(d(),f("div",St,"错误信息:"+v(ee(t)),1)):h("",!0)]),r("div",Tt,[r("span",{class:Oe(["status",ae(t).className])},v(ae(t).text),3),Ne(t)?(d(),f("button",{key:0,type:"button",class:"download",onClick:a=>Pe(t)}," 下载 ",8,Ct)):h("",!0),t.resultId?(d(),f("button",{key:1,type:"button",class:"btn-delete",onClick:a=>$e(t.resultId)}," 删除 ",8,Rt)):h("",!0)])]))),128))])])):h("",!0)],64)):(d(),f("div",Hs," 暂无删除品牌结果,完成解析后会在这里展示按国家分组的去重结果 "))])])])])]))}}),Et=gs(Nt,[["__scopeId","data-v-13de5e1b"]]);ms(Et).use(ks).mount("#app"); +import{d as ns,o as ls,M as rs,a as d,c as f,b as os,B as us,e as r,F as V,r as ye,t as v,f as h,N as is,O as qe,n as Oe,g as y,h as z,P as cs,i as ne,E as p,Q as ds,R as fs,S as vs,s as hs,T as ps,U as _s,V as ys,_ as gs,q as ms,u as ks}from"./java-modules-B8c-YG5x.js";import{e as ws}from"./brand-COze15GJ.js";import{c as Is}from"./categorized-timers-JPA-olTr.js";const bs={class:"page-shell module-page"},Ss={class:"main-content"},Ts={class:"left-panel"},Cs={class:"upload-zone"},Rs={class:"selected-files clean-placeholder split-selected-files"},Ns={key:0,class:"more-line"},Es={key:1},Fs={class:"run-row"},Ps=["disabled"],xs=["disabled"],$s={class:"loading-msg"},As={key:0,class:"queue-debug-card"},Ds={key:0,class:"queue-debug-line"},Ms={key:1,class:"queue-debug-payload"},Bs={class:"right-panel"},Us={class:"task-list-wrap"},Ls={class:"clean-result-summary"},qs={class:"summary-card"},Os={class:"summary-card"},Ks={class:"summary-card"},Gs={class:"result-list-wrap"},Hs={key:0,class:"empty-tasks"},Js={key:0,class:"result-subsection"},js={class:"task-list clean-result-list"},Vs={class:"left split-result-main"},zs=["title"],Qs={class:"files"},Xs={class:"files"},Ws={key:0,class:"files"},Ys={key:1,class:"files"},Zs={key:2,class:"files"},et={key:3,class:"time"},st={key:4,class:"delete-brand-progress-block"},tt={class:"delete-brand-progress-header"},at={class:"delete-brand-progress-bar"},nt={class:"files delete-brand-progress"},lt={key:5,class:"files split-entry-list delete-brand-preview"},rt={key:6,class:"files"},ot={class:"task-right split-result-actions"},ut=["onClick"],it=["onClick"],ct={key:1,class:"result-subsection"},dt={class:"task-list clean-result-list"},ft={class:"left split-result-main"},vt=["title"],ht={class:"files"},pt={class:"files"},_t={key:0,class:"files"},yt={key:1,class:"files"},gt={key:2,class:"time"},mt={key:3,class:"delete-brand-progress-block"},kt={class:"delete-brand-progress-header"},wt={class:"delete-brand-progress-bar"},It={class:"files delete-brand-progress"},bt={key:4,class:"files split-entry-list delete-brand-preview"},St={key:5,class:"files"},Tt={class:"task-right split-result-actions"},Ct=["onClick"],Rt=["onClick"],Nt=ns({__name:"BrandDeleteBrandTab",setup(Ft){function D(){return`delete-brand:current-tasks:${typeof window<"u"&&window.localStorage.getItem("uid")||"0"}`}const M=y([]),Q=y([]),O=y(!1),ge=y([]),i=y([]),K=y([]),X=y({total:0,successCount:0,failedCount:0,items:[]}),b=y(""),S=y(""),m=y({}),T=y(null),le=y(!1),W=y(!1),R=y(!1),B=y(""),Y=y(!1),G=y(null),re=y(!1);let U=!1;const L=Is("delete-brand"),oe=z(()=>M.value.slice(0,10)),N=z(()=>{const e=[...i.value].sort((t,a)=>(a.createdAt||0)-(t.createdAt||0)),s=[];return e.forEach(t=>{s.push(...t.items)}),s});function Ke(){try{const e=typeof window<"u"?window.localStorage.getItem(D()):null;if(e){if(i.value=JSON.parse(e),i.value.length>0){const s=i.value[i.value.length-1];b.value=s.queuePushResult||"",S.value=s.queuePayloadText||""}}else i.value=[]}catch{i.value=[]}}function ue(e,s,t,a){if(!s?.length)return;const l=i.value.findIndex(c=>c.taskId===e),o=l>=0?i.value[l]:null,n=s.map(c=>{const _=o?.items.find(as=>q(as,c)),k=Array.isArray(c.countries)?c.countries:void 0,g=Array.isArray(_?.countries)?_?.countries:void 0,w=k&&k.length>0?k:g&&g.length>0?g:k??g,I=Array.isArray(c.previewRows)?c.previewRows:void 0,C=Array.isArray(_?.previewRows)?_?.previewRows:void 0,_e=I&&I.length>0?I:C&&C.length>0?C:I??C;return{...c,countries:w,previewRows:_e,_pushed:_?._pushed??c._pushed??!1,_completed:_?._completed??c._completed??!1}}),u={taskId:e,items:n,createdAt:o?.createdAt||Date.now(),queuePushResult:t??o?.queuePushResult,queuePayloadText:a??o?.queuePayloadText};l>=0?i.value[l]=u:i.value.push(u),typeof window<"u"&&window.localStorage.setItem(D(),JSON.stringify(i.value))}function me(e){const s=i.value.length;i.value=i.value.filter(t=>t.taskId!==e),i.value.length!==s&&typeof window<"u"&&window.localStorage.setItem(D(),JSON.stringify(i.value))}function ke(e){return e==="SUCCESS"||e==="FAILED"||e==="COMPLETED"}function Ge(e){if(!e?.length)return!1;const s=new Set;if(e.forEach(a=>{a.taskId&&ke(a.taskStatus)&&s.add(a.taskId)}),!s.size)return!1;const t=i.value.length;return i.value=i.value.filter(a=>!s.has(a.taskId)),i.value.length!==t?(ie(),!0):!1}const Z=z(()=>K.value.filter(e=>!N.value.some(s=>q(s,e)))),He=z(()=>N.value.length>0||Z.value.length>0),Je=z(()=>N.value.filter(e=>Me(e)&&E(e)==="未入队"));function ie(){typeof window<"u"&&(i.value.length===0?window.localStorage.removeItem(D()):window.localStorage.setItem(D(),JSON.stringify(i.value)))}function P(e){return e?(i.value.find(t=>t.taskId===e)?.items.length||0)>1:!1}function ce(e){return e&&i.value.find(s=>s.taskId===e)||null}function q(e,s){return!e||!s?!1:e.resultId!=null&&s.resultId!=null?e.resultId===s.resultId:e.fileKey&&s.fileKey?e.fileKey===s.fileKey:e.sourceFilename===s.sourceFilename}function x(e,s){const t=ce(e);return t&&t.items.find(a=>q(a,s))||null}function we(e){if(!e)return!1;const s=ce(e);if(!s)return!1;let t=!1;const a=m.value[e]?.line_progress?.info,l=P(e);if(a?.file_name&&a.current_line!=null&&a.total_lines!=null&&a.total_lines>0&&a.current_line>=a.total_lines){const o=s.items.find(n=>n.sourceFilename===a.file_name);o&&!o._completed&&(o._completed=!0,t=!0)}if(!l){const o=m.value[e]?.task?.status;if((o==="SUCCESS"||o==="FAILED")&&s.items.length===1){const n=s.items[0];n&&!n._completed&&(n._completed=!0,t=!0)}}return t&&ie(),t}function Ie(e){return e&&m.value[e]?.task?.status||""}function ee(e){if(e.error)return e.error;if(e.matchStatus&&e.matchStatus!=="MATCHED")return e.matchMessage||"";const s=e.taskId;return s&&m.value[s]?.task?.errorMessage||""}function be(e){const s=e.taskId;if(!s)return!1;const t=m.value[s]?.line_progress,a=Ie(s),l=P(s),o=E(e);if(l){const n=x(s,e),u=j(e)===B.value,c=!!(t?.has_progress&&t?.info?.file_name===e.sourceFilename);return u||c||n?._pushed||(a==="RUNNING"||a==="PENDING"||!a)&&n?._completed?!0:{success:!1,retryable:!0}}return o==="本文件解析完毕"||o==="已被全局判定为终态"?!1:t?.has_progress||t?.info?!0:o==="已入队"||o==="处理中"}function Se(e){return e.map(s=>A(s)?{...s,matched:!0,_pushed:!1,_completed:!1}:{...s,matched:!1,openStoreUrl:void 0,error:s.error||void 0,_pushed:!1,_completed:!1})}function Te(e){return e.matchStatus==="INDEX_STALE"&&A(e)?`已匹配 ${e.shopId||""}(索引过期,可继续推送)`.trim():e.matchStatus==="MATCHED"||e.matched?`已匹配 ${e.shopId||""}`.trim():e.matchMessage?e.matchMessage:e.matchStatus==="CONFLICT"?"存在多个同名店铺,请人工确认":e.matchStatus==="PENDING"?"店铺索引暂未就绪":e.matchStatus?e.matchStatus:e.matched?`已匹配 ${e.shopId||""}`.trim():"待匹配"}function je(){ge.value=[...N.value,...Z.value]}function $(){je(),Ve(ge.value)}function Ve(e){X.value={total:e.length,successCount:e.filter(s=>s.success).length,failedCount:e.filter(s=>!s.success).length,items:e}}function de(e){const s=e.taskId;return s&&(m.value[s]?.fileProgress||[]).find(l=>l.fileKey&&e.fileKey?l.fileKey===e.fileKey:l.sourceFilename&&e.sourceFilename?l.sourceFilename===e.sourceFilename:!1)||null}function Ce(e){const s=e.taskId;if(!s)return"";const t=m.value[s],a=t?.line_progress?.info,l=de(e);if(P(s)){const u=x(s,e),c=t?.task?.status,_=!!(a?.file_name&&a.file_name===e.sourceFilename);let k=u?._completed?"COMPLETED":(u?._pushed,"PENDING"),g=0,w=Math.max(0,e.totalRows??l?.totalRows??0);c==="SUCCESS"||c==="FAILED"&&u?._completed?(k="COMPLETED",g=w):_?(k="RUNNING",g=Math.max(0,Math.min(w||Number.MAX_SAFE_INTEGER,a?.current_line??0)),!w&&a?.total_lines&&a.total_lines>0&&(w=a.total_lines)):u?._completed?(k="COMPLETED",g=w):u?._pushed&&(k="PENDING",g=0);const I=[];if(I.push(`文件状态:${k}`),I.push(`文件进度:${g}/${w}`),a?.finished_files!=null){const C=a.file_total&&a.file_total>0?`/${a.file_total}`:"";I.push(`已完成文件:${a.finished_files}${C}`)}return a?.phase&&I.push(`阶段:${a.phase}`),I.join("|")}if(l){const u=[],c=l.processedRows??0,_=l.totalRows??0;if(l.status&&u.push(`文件状态:${l.status}`),u.push(`文件进度:${c}/${_}`),a?.finished_files!=null){const k=a.file_total&&a.file_total>0?`/${a.file_total}`:"";u.push(`已完成文件:${a.finished_files}${k}`)}return a?.phase&&u.push(`阶段:${a.phase}`),u.join("|")}if(!t?.line_progress?.has_progress||!a){const u=t?.task?.status;return u?`任务状态:${u}`:""}const n=[];if(a.phase&&n.push(`阶段:${a.phase}`),a.file_index&&a.file_total&&n.push(`文件:${a.file_index}/${a.file_total}`),a.file_name&&n.push(`当前文件:${a.file_name}`),a.current_line!=null&&a.total_lines!=null&&n.push(`${P(s)?"当前文件进度":"进度"}:${a.current_line}/${a.total_lines}`),a.current_country&&n.push(`国家:${a.current_country}`),a.current_asin&&n.push(`ASIN:${a.current_asin}`),a.finished_files!=null){const u=a.file_total&&a.file_total>0?`/${a.file_total}`:"";n.push(`已完成文件:${a.finished_files}${u}`)}return n.join("|")}function se(e){const s=e.taskId;if(!s)return 0;const t=m.value[s]?.line_progress?.info;if(P(s)){const n=x(s,e);if(m.value[s]?.task?.status==="SUCCESS"||n?._completed)return 100;const c=Math.max(0,e.totalRows??de(e)?.totalRows??0);if(!!(t?.file_name&&t.file_name===e.sourceFilename)){if(t?.current_line!=null&&t?.total_lines&&t.total_lines>0)return Math.max(0,Math.min(100,Math.round(t.current_line/t.total_lines*100)));if(t?.current_line!=null&&c>0)return Math.max(0,Math.min(100,Math.round(t.current_line/c*100)))}return 0}const l=de(e);return l?Math.max(0,Math.min(100,l.percent??0)):t?t.current_line!=null&&t.total_lines&&t.total_lines>0?Math.max(0,Math.min(100,Math.round(t.current_line/t.total_lines*100))):t.finished_files!=null&&t.file_total&&t.file_total>0?Math.max(0,Math.min(100,Math.round(t.finished_files/t.file_total*100))):m.value[s]?.task?.status==="SUCCESS"?100:0:0}function Re(e){const s=m.value[e]?.task?.status;return ke(s)}function H(){const e=new Set;return i.value.forEach(s=>{s.items.some(t=>t._pushed)&&e.add(s.taskId)}),Array.from(e)}function E(e){const s=e.taskId;if(!s||!ce(s))return"";const a=x(s,e),l=Ie(s),o=m.value[s]?.line_progress,n=P(s);if(!n&&(l==="SUCCESS"||l==="FAILED"||e.taskStatus==="SUCCESS"||e.taskStatus==="FAILED"))return"已被全局判定为终态";if(te(e)||te(a)||a?._completed)return"本文件解析完毕";if(l==="RUNNING"&&o?.has_progress&&o?.info?.file_name===e.sourceFilename)return"处理中";if(n&&!a?._pushed&&!a?._completed)return"未入队";if(n&&l==="SUCCESS")return"本文件解析完毕";if(!n){const u=m.value[s];if(u?.items&&u.items.find(_=>q(_,e))&&l==="SUCCESS")return"本文件解析完毕"}return a?._pushed?"已入队":"未入队"}function Ne(e){return!!(e.downloadUrl||e.fileReady)}function te(e){if(!e)return!1;const s=String(e.fileStatus||"").toUpperCase();return!!(e.fileReady||e.downloadUrl||s==="SUCCESS"||s==="COMPLETED")}function F(e,s){return e??s}function ze(e){const s=e?.task?.id;if(!s)return!1;const t=i.value.find(n=>n.taskId===s);if(!t)return{success:!1,retryable:!1};const a=e?.items||[];let l=!1;const o=t.items.map(n=>{const u=a.find(_e=>q(_e,n));if(!u)return n;const c=Array.isArray(u.countries)?u.countries:void 0,_=Array.isArray(n.countries)?n.countries:void 0,k=c&&c.length>0?c:_&&_.length>0?_:c??_,g=Array.isArray(u.previewRows)?u.previewRows:void 0,w=Array.isArray(n.previewRows)?n.previewRows:void 0,I=g&&g.length>0?g:w&&w.length>0?w:g??w,C={...n,...u,shopName:F(u.shopName,n.shopName),companyName:F(u.companyName,n.companyName),shopId:F(u.shopId,n.shopId),platform:F(u.platform,n.platform),openStoreUrl:F(u.openStoreUrl,n.openStoreUrl),matchStatus:F(u.matchStatus,n.matchStatus),matchMessage:F(u.matchMessage,n.matchMessage),matched:A(n)||A(u),countryCount:F(u.countryCount,n.countryCount),countries:k,previewRows:I,_pushed:n._pushed,_completed:n._completed||te(u)};return JSON.stringify(C)!==JSON.stringify(n)&&(l=!0),C});for(const n of a)o.some(u=>q(u,n))||(o.push({...n,_pushed:!1,_completed:te(n)}),l=!0);return JSON.stringify(o)!==JSON.stringify(t.items)&&(t.items=o,l=!0),l&&ie(),l}async function fe(e){const s=e||H();if(s.length)try{const t=await cs(s);re.value&&R.value&&(b.value="后端已恢复,继续执行当前任务并自动衔接后续任务..."),re.value=!1;let a=!1;for(const l of t.items||[]){const o=l?.task?.id;typeof o=="number"&&o>0&&(m.value[o]=l,ze(l)&&(a=!0),we(o)&&(a=!0))}a&&$()}catch(t){const a=(t instanceof Error?t.message:String(t||"")).toLowerCase();["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(o=>a.includes(o.toLowerCase()))&&R.value&&(re.value=!0,b.value="当前任务运行中,正在等待后端服务恢复...")}}function Qe(){return ys()}function ve(e=!1){if(U)return;if(T.value){if(!e)return;L.clearTimer("task-poll",T.value),T.value=null}const s=async()=>{if(T.value=null,U)return;if(le.value){ve();return}const t=H();if(!t.length)return;le.value=!0;let a=!1,l=!1;try{await fe(t),await Le();for(const o of t)Re(o)&&(me(o),a=!0,l=!0)}finally{le.value=!1}l?await J():a&&$(),!U&&H().length>0&&ve()};e?s():T.value=L.setTimeout("task-poll",s,Qe())}function he(e=!1){T.value&&!e||ve(e)}function ae(e){if(e.fileReady||e.downloadUrl)return{className:"success",text:"已完成"};const s=e.taskId?m.value[e.taskId]?.task?.status:null;return s==="SUCCESS"?{className:"success",text:"已完成"}:s==="FAILED"?{className:"failed",text:"失败"}:s==="RUNNING"?{className:"running",text:"执行中"}:e.taskStatus==="SUCCESS"?{className:"success",text:"已完成"}:e.taskStatus==="FAILED"?{className:"failed",text:"失败"}:e.taskStatus==="RUNNING"?{className:"running",text:"执行中"}:e.success?{className:"success",text:"已完成"}:{className:"failed",text:"失败"}}function Ee(){T.value&&(L.clearTimer("task-poll",T.value),T.value=null),pe()}async function Fe(e){const s=ne();if(!s?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const a of e){const l=typeof a=="string"?a:a.absolutePath,o=typeof a=="string"?void 0:a.relativePath,n=await s.upload_file_to_java(l,o);if(!n?.success||!n.data)throw new Error(n?.error||n?.message||`上传失败:${l}`);t.push(n.data)}return t}async function Xe(){const e=ne();if(!e?.select_brand_xlsx_files){p.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const s=await e.select_brand_xlsx_files();if(!s?.length)return;M.value=s,Q.value=await Fe(s),p.success(`已选择 ${s.length} 个删除品牌文件`)}catch(s){p.error(s instanceof Error?s.message:"选择失败")}}async function We(){const e=ne();if(!e?.select_brand_folder){p.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const s=await e.select_brand_folder();if(!s)return;const t=await ws(s);if(!t.success||!t.items?.length){p.warning(t.error||"该文件夹下没有 xlsx 文件");return}M.value=t.items.map(a=>a.relativePath||a.absolutePath),Q.value=await Fe(t.items),p.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`)}catch(s){p.error(s instanceof Error?s.message:"选择失败")}}async function Ye(){if(!Q.value.length){p.warning("请先选择待处理文件");return}try{O.value=!0;const e=await ds({files:Q.value.map(o=>({fileKey:o.fileKey,originalFilename:o.originalFilename,relativePath:o.relativePath}))}),s=Se(e.items||[]),t=s.some(o=>A(o)),a=s.some(o=>o.matchStatus==="INDEX_STALE"&&o.matched),l=s.some(o=>!A(o));b.value=t?"解析完成,可在左侧点击“推送到 Python 队列”开始串行处理":"解析完成,当前没有可推送的文件",S.value="",s.length&&s[0].taskId&&ue(s[0].taskId,s,b.value,S.value),$(),l?p.warning("部分文件尚未命中可用店铺索引,已保留状态信息,请等待后台刷新后重试。"):a?p.warning("部分文件命中的是过期索引,仍可推送到 Python 队列;后台刷新后会自动重新匹配。"):t?p.success("删除品牌解析完成,请在左侧推送到 Python 队列"):p.warning("当前没有可推送的文件,请先等待店铺索引刷新。"),await J()}catch(e){p.error(e instanceof Error?e.message:"执行失败")}finally{O.value=!1}}async function Pe(e){const s=e.taskId;if(!s){p.warning("未找到任务ID");return}const t=e.resultId?fs(e.resultId):vs(s),a=e.outputFilename||e.sourceFilename||`delete-brand_${s}.xlsx`,l=await hs(t,a,e.resultId?`delete-brand:${e.resultId}`:`delete-brand-task:${s}`);l.success?p.success(`已保存:${l.path||a}`):l.error&&l.error!=="用户取消"&&p.error(l.error)}async function J(){try{const e=await ps();K.value=Se(e.items||[]),Ge(K.value),$(),await fe(),he(!0)}catch(e){const s=(e instanceof Error?e.message:String(e||"")).toLowerCase();["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(a=>s.includes(a.toLowerCase()))||console.error("loadHistory error:",e)}}function xe(e){i.value.forEach(t=>{t.items=t.items.filter(a=>a.resultId!==e)});const s=i.value.length;i.value=i.value.filter(t=>t.items.length>0),i.value.length!==s&&typeof window<"u"&&window.localStorage.setItem(D(),JSON.stringify(i.value)),K.value=K.value.filter(t=>t.resultId!==e),$(),H().length===0&&Ee()}async function $e(e){try{await _s(e),xe(e),await J(),p.success("已删除")}catch(s){const t=s instanceof Error?s.message:"删除失败";if(typeof t=="string"&&t.includes("记录不存在")){xe(e),p.success("已删除");return}p.error(t)}}function Ae(e){const s=e.slice(0,5).map(a=>`${a.country}:${a.asin}${a.status?`(${a.status})`:""}`);return e.length-s.length>0?`${s.join("、")} 等 ${e.length} 条`:s.join("、")}function Pt(e,s){}function pe(){G.value&&(L.clearTimer("auto-retry",G.value),G.value=null)}function Ze(e=3e3){U||(pe(),G.value=L.setTimeout("auto-retry",()=>{G.value=null,U||Le().catch(()=>{})},e))}function es(e){return e.includes("当前店铺正在执行中")}function De(){for(const e of i.value)for(const s of e.items){const t=E(s);if(t==="已入队"||t==="处理中")return!0}return!1}function j(e){return e.resultId!=null?`result:${e.resultId}`:`task:${e.taskId||0}:${e.sourceFilename||""}`}function A(e){return!!(e.matched||e.matchStatus==="MATCHED"||e.matchStatus==="INDEX_STALE"&&e.shopId)}function ss(e){return!!(e.shopName&&Array.isArray(e.countries)&&e.countries.length>0)}function Me(e){return!!(e.taskId&&(A(e)||ss(e)))}function Be(){return N.value.find(e=>!Me(e)||j(e)===B.value||x(e.taskId,e)?._completed?!1:E(e)==="未入队")}async function Ue(e,s){if(s?.auto&&De())return e.taskId,e.sourceFilename,{success:!1,retryable:!0};const t=ne(),a=e.taskId;if(!a)return{success:!1,retryable:!1};const l=i.value.find(c=>c.taskId===a);if(!l)return{success:!1,retryable:!1};if(!t?.enqueue_json)return p.error("当前环境未启用 pywebview enqueue_json(浏览器环境不会推送)"),{success:!1,retryable:!1};const o={type:"delete-brand-run",ts:Date.now(),data:{taskId:a,items:[e]}};S.value=JSON.stringify(o,null,2);const n=await t.enqueue_json(o);let u="";if(n?.success){u=`已推送文件 ${e.sourceFilename},当前队列长度:${n.queue_size??"-"}`;const c=x(a,e);return c&&(c._pushed=!0,c._completed=!1),B.value=j(e),ue(a,l.items,u,S.value),he(!0),b.value=u,{success:!0,retryable:!1}}else{const c=n?.error||"未知错误";if(u=`推送到 Python 队列失败:${c}`,b.value=u,ue(a,l.items,u,S.value),s?.auto&&es(c))return{success:!1,retryable:!0}}return b.value=u,{success:!1,retryable:!1}}async function ts(){const e=Be();if(!e){p.warning("当前没有可推送的文件");return}W.value=!0,R.value=!0,pe();const s=await Ue(e);if(W.value=!1,!s.success){R.value=!1,B.value="";return}p.success("已开始按顺序推送到 Python 队列")}async function Le(){if(!R.value||Y.value){R.value,Y.value;return}if(De())return;const e=B.value;if(e){const t=N.value.find(a=>j(a)===e);if(t){const a=t.taskId,l=P(a);l&&(we(a),E(t),void 0);const o=E(t);if(o==="已入队"||o==="处理中"){t.sourceFilename;return}if(l){const n=x(a,t);if(n&&!n._completed){t.sourceFilename,n._pushed,n._completed;return}}}}const s=Be();if(!s){B.value="",R.value=!1;return}Y.value=!0;try{s.taskId,s.sourceFilename,j(s);const t=await Ue(s,{auto:!0});if(!t.success){if(t.retryable){s.taskId,s.sourceFilename,Ze();return}s.taskId,s.sourceFilename,R.value=!1}}finally{Y.value=!1}}return ls(()=>{Ke();const e=H();e.length>0?fe(e).then(async()=>{let s=!1,t=!1;for(const a of e)Re(a)&&(me(a),s=!0,t=!0);t?await J():s&&$(),he(!0)}):$(),J().catch(()=>{})}),rs(()=>{U=!0,Ee(),L.clearScope()}),(e,s)=>(d(),f("div",bs,[os(us,{active:"delete-brand"}),r("div",Ss,[r("aside",Ts,[s[2]||(s[2]=r("div",{class:"section-title"},"选择文件",-1)),r("div",Cs,[s[0]||(s[0]=r("div",{class:"hint"},"上传删除品牌 Excel;无论是直接上传文件还是上传文件夹批量导入,都会按每个 Excel 文件名作为店铺名。",-1)),r("div",{class:"btns"},[r("button",{type:"button",class:"opt-btn",onClick:Xe},"选择 Excel 文件"),r("button",{type:"button",class:"opt-btn",onClick:We},"选择文件夹")]),r("div",Rs,[M.value.length?(d(),f(V,{key:0},[(d(!0),f(V,null,ye(oe.value,t=>(d(),f("span",{key:t},v(t),1))),128)),M.value.length>oe.value.length?(d(),f("span",Ns," 还有 "+v(M.value.length-oe.value.length)+" 个文件未展开显示 ",1)):h("",!0)],64)):(d(),f("span",Es,"暂未选择删除品牌文件"))])]),s[3]||(s[3]=is('
执行说明
',2)),r("div",Fs,[r("button",{type:"button",class:"btn-run",disabled:O.value,onClick:Ye},v(O.value?"解析中...":"开始解析"),9,Ps),r("button",{type:"button",class:"btn-run btn-queue",disabled:W.value||!Je.value.length,onClick:ts},v(W.value?"推送中...":"推送到 Python 队列"),9,xs),r("span",$s,v(O.value?"正在读取删除品牌数据,请稍候…":"解析后会在右侧展示按国家分组的去重结果"),1)]),b.value||S.value?(d(),f("div",As,[s[1]||(s[1]=r("div",{class:"section-title queue-debug-title"},"Python 队列推送结果",-1)),b.value?(d(),f("div",Ds,v(b.value),1)):h("",!0),S.value?(d(),f("pre",Ms,v(S.value),1)):h("",!0)])):h("",!0)]),r("section",Bs,[s[12]||(s[12]=r("div",{class:"panel-header"},"删除品牌结果",-1)),r("div",Us,[r("div",Ls,[r("div",qs,[s[4]||(s[4]=r("span",{class:"summary-label"},"已处理文件",-1)),r("strong",null,v(X.value.total),1)]),r("div",Os,[s[5]||(s[5]=r("span",{class:"summary-label"},"成功结果",-1)),r("strong",null,v(X.value.successCount),1)]),r("div",Ks,[s[6]||(s[6]=r("span",{class:"summary-label"},"失败文件",-1)),r("strong",null,v(X.value.failedCount),1)])]),r("div",Gs,[s[11]||(s[11]=r("div",{class:"result-list-header"},[r("span",null,"删除品牌结果列表")],-1)),He.value?(d(),f(V,{key:1},[N.value.length?(d(),f("div",Js,[s[8]||(s[8]=r("div",{class:"result-subsection-title"},"当前任务",-1)),r("ul",js,[(d(!0),f(V,null,ye(N.value,t=>(d(),f("li",{key:`current-${t.taskId||t.resultId||t.sourceFilename}`,class:"task-item split-result-item"},[r("div",Vs,[r("span",{class:"id",title:t.sourceFilename},v(t.sourceFilename||"-"),9,zs),r("div",Qs,"店铺名:"+v(t.shopName||"-"),1),r("div",Xs,"匹配结果:"+v(Te(t)),1),t.platform?(d(),f("div",Ws,"平台:"+v(t.platform),1)):h("",!0),E(t)?(d(),f("div",Ys,"队列状态:"+v(E(t)),1)):h("",!0),t.countryCount!==void 0&&t.matched?(d(),f("div",Zs,"国家数:"+v(t.countryCount),1)):h("",!0),t.totalRows!==void 0&&t.matched?(d(),f("div",et,"去重后 "+v(t.totalRows)+" 条 ",1)):h("",!0),be(t)?(d(),f("div",st,[r("div",tt,[s[7]||(s[7]=r("span",null,"任务进度",-1)),r("span",null,v(se(t))+"%",1)]),r("div",at,[r("div",{class:"delete-brand-progress-bar-fill",style:qe({width:`${se(t)}%`})},null,4)]),r("div",nt,v(Ce(t)),1)])):h("",!0),t.previewRows?.length?(d(),f("div",lt,v(Ae(t.previewRows)),1)):h("",!0),ee(t)?(d(),f("div",rt,"错误信息:"+v(ee(t)),1)):h("",!0)]),r("div",ot,[r("span",{class:Oe(["status",ae(t).className])},v(ae(t).text),3),Ne(t)?(d(),f("button",{key:0,type:"button",class:"download",onClick:a=>Pe(t)}," 下载 ",8,ut)):h("",!0),t.resultId?(d(),f("button",{key:1,type:"button",class:"btn-delete",onClick:a=>$e(t.resultId)}," 删除 ",8,it)):h("",!0)])]))),128))])])):h("",!0),Z.value.length?(d(),f("div",ct,[s[10]||(s[10]=r("div",{class:"result-subsection-title"},"历史记录",-1)),r("ul",dt,[(d(!0),f(V,null,ye(Z.value,t=>(d(),f("li",{key:`history-${t.taskId||t.resultId||t.sourceFilename}`,class:"task-item split-result-item"},[r("div",ft,[r("span",{class:"id",title:t.sourceFilename},v(t.sourceFilename||"-"),9,vt),r("div",ht,"店铺名:"+v(t.shopName||"-"),1),r("div",pt,"匹配结果:"+v(Te(t)),1),t.platform?(d(),f("div",_t,"平台:"+v(t.platform),1)):h("",!0),t.countryCount!==void 0&&t.matched?(d(),f("div",yt,"国家数:"+v(t.countryCount),1)):h("",!0),t.totalRows!==void 0&&t.matched?(d(),f("div",gt,"去重后 "+v(t.totalRows)+" 条 ",1)):h("",!0),be(t)?(d(),f("div",mt,[r("div",kt,[s[9]||(s[9]=r("span",null,"任务进度",-1)),r("span",null,v(se(t))+"%",1)]),r("div",wt,[r("div",{class:"delete-brand-progress-bar-fill",style:qe({width:`${se(t)}%`})},null,4)]),r("div",It,v(Ce(t)),1)])):h("",!0),t.previewRows?.length?(d(),f("div",bt,v(Ae(t.previewRows)),1)):h("",!0),ee(t)?(d(),f("div",St,"错误信息:"+v(ee(t)),1)):h("",!0)]),r("div",Tt,[r("span",{class:Oe(["status",ae(t).className])},v(ae(t).text),3),Ne(t)?(d(),f("button",{key:0,type:"button",class:"download",onClick:a=>Pe(t)}," 下载 ",8,Ct)):h("",!0),t.resultId?(d(),f("button",{key:1,type:"button",class:"btn-delete",onClick:a=>$e(t.resultId)}," 删除 ",8,Rt)):h("",!0)])]))),128))])])):h("",!0)],64)):(d(),f("div",Hs," 暂无删除品牌结果,完成解析后会在这里展示按国家分组的去重结果 "))])])])])]))}}),Et=gs(Nt,[["__scopeId","data-v-13de5e1b"]]);ms(Et).use(ks).mount("#app"); diff --git a/app/assets/java-modules-DzYrjxib.js b/app/assets/java-modules-B8c-YG5x.js similarity index 99% rename from app/assets/java-modules-DzYrjxib.js rename to app/assets/java-modules-B8c-YG5x.js index ee68edb..0c18cb2 100644 --- a/app/assets/java-modules-DzYrjxib.js +++ b/app/assets/java-modules-B8c-YG5x.js @@ -52,4 +52,4 @@ usage: app.provide(ZINDEX_INJECTION_KEY, { current: 0 })`),{initialZIndex:o,curr `)}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...n){const o=new this(t);return n.forEach(a=>o.set(a)),o}static accessor(t){const o=(this[mw]=this[mw]={accessors:{}}).accessors,a=this.prototype;function s(r){const l=Xl(r);o[l]||($ee(a,r),o[l]=!0)}return xe.isArray(t)?t.forEach(s):s(t),this}};wo.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);xe.reduceDescriptors(wo.prototype,({value:e},t)=>{let n=t[0].toUpperCase()+t.slice(1);return{get:()=>e,set(o){this[n]=o}}});xe.freezeMethods(wo);function Cp(e,t){const n=this||Ru,o=t||n,a=wo.from(o.headers);let s=o.data;return xe.forEach(e,function(l){s=l.call(n,s,a.normalize(),t?t.status:void 0)}),a.normalize(),s}function Bx(e){return!!(e&&e.__CANCEL__)}let Nu=class extends At{constructor(t,n,o){super(t??"canceled",At.ERR_CANCELED,n,o),this.name="CanceledError",this.__CANCEL__=!0}};function Fx(e,t,n){const o=n.config.validateStatus;!n.status||!o||o(n.status)?e(n):t(new At("Request failed with status code "+n.status,[At.ERR_BAD_REQUEST,At.ERR_BAD_RESPONSE][Math.floor(n.status/100)-4],n.config,n.request,n))}function Oee(e){const t=/^([-+\w]{1,25})(:?\/\/|:)/.exec(e);return t&&t[1]||""}function Ree(e,t){e=e||10;const n=new Array(e),o=new Array(e);let a=0,s=0,r;return t=t!==void 0?t:1e3,function(u){const c=Date.now(),d=o[s];r||(r=c),n[a]=u,o[a]=c;let f=s,v=0;for(;f!==a;)v+=n[f++],f=f%e;if(a=(a+1)%e,a===s&&(s=(s+1)%e),c-r{n=d,a=null,s&&(clearTimeout(s),s=null),e(...c)};return[(...c)=>{const d=Date.now(),f=d-n;f>=o?r(c,d):(a=c,s||(s=setTimeout(()=>{s=null,r(a)},o-f)))},()=>a&&r(a)]}const xd=(e,t,n=3)=>{let o=0;const a=Ree(50,250);return Nee(s=>{const r=s.loaded,l=s.lengthComputable?s.total:void 0,u=r-o,c=a(u),d=r<=l;o=r;const f={loaded:r,total:l,progress:l?r/l:void 0,bytes:u,rate:c||void 0,estimated:c&&l&&d?(l-r)/c:void 0,event:s,lengthComputable:l!=null,[t?"download":"upload"]:!0};e(f)},n)},gw=(e,t)=>{const n=e!=null;return[o=>t[0]({lengthComputable:n,total:e,loaded:o}),t[1]]},bw=e=>(...t)=>xe.asap(()=>e(...t)),Iee=Qn.hasStandardBrowserEnv?((e,t)=>n=>(n=new URL(n,Qn.origin),e.protocol===n.protocol&&e.host===n.host&&(t||e.port===n.port)))(new URL(Qn.origin),Qn.navigator&&/(msie|trident)/i.test(Qn.navigator.userAgent)):()=>!0,_ee=Qn.hasStandardBrowserEnv?{write(e,t,n,o,a,s,r){if(typeof document>"u")return;const l=[`${e}=${encodeURIComponent(t)}`];xe.isNumber(n)&&l.push(`expires=${new Date(n).toUTCString()}`),xe.isString(o)&&l.push(`path=${o}`),xe.isString(a)&&l.push(`domain=${a}`),s===!0&&l.push("secure"),xe.isString(r)&&l.push(`SameSite=${r}`),document.cookie=l.join("; ")},read(e){if(typeof document>"u")return null;const t=document.cookie.match(new RegExp("(?:^|; )"+e+"=([^;]*)"));return t?decodeURIComponent(t[1]):null},remove(e){this.write(e,"",Date.now()-864e5,"/")}}:{write(){},read(){return null},remove(){}};function Pee(e){return typeof e!="string"?!1:/^([a-z][a-z\d+\-.]*:)?\/\//i.test(e)}function Mee(e,t){return t?e.replace(/\/?\/$/,"")+"/"+t.replace(/^\/+/,""):e}function Vx(e,t,n){let o=!Pee(t);return e&&(o||n==!1)?Mee(e,t):t}const yw=e=>e instanceof wo?{...e}:e;function $r(e,t){t=t||{};const n={};function o(c,d,f,v){return xe.isPlainObject(c)&&xe.isPlainObject(d)?xe.merge.call({caseless:v},c,d):xe.isPlainObject(d)?xe.merge({},d):xe.isArray(d)?d.slice():d}function a(c,d,f,v){if(xe.isUndefined(d)){if(!xe.isUndefined(c))return o(void 0,c,f,v)}else return o(c,d,f,v)}function s(c,d){if(!xe.isUndefined(d))return o(void 0,d)}function r(c,d){if(xe.isUndefined(d)){if(!xe.isUndefined(c))return o(void 0,c)}else return o(void 0,d)}function l(c,d,f){if(f in t)return o(c,d);if(f in e)return o(void 0,c)}const u={url:s,method:s,data:s,baseURL:r,transformRequest:r,transformResponse:r,paramsSerializer:r,timeout:r,timeoutMessage:r,withCredentials:r,withXSRFToken:r,adapter:r,responseType:r,xsrfCookieName:r,xsrfHeaderName:r,onUploadProgress:r,onDownloadProgress:r,decompress:r,maxContentLength:r,maxBodyLength:r,beforeRedirect:r,transport:r,httpAgent:r,httpsAgent:r,cancelToken:r,socketPath:r,responseEncoding:r,validateStatus:l,headers:(c,d,f)=>a(yw(c),yw(d),f,!0)};return xe.forEach(Object.keys({...e,...t}),function(d){if(d==="__proto__"||d==="constructor"||d==="prototype")return;const f=xe.hasOwnProp(u,d)?u[d]:a,v=f(e[d],t[d],d);xe.isUndefined(v)&&f!==l||(n[d]=v)}),n}const zx=e=>{const t=$r({},e);let{data:n,withXSRFToken:o,xsrfHeaderName:a,xsrfCookieName:s,headers:r,auth:l}=t;if(t.headers=r=wo.from(r),t.url=Lx(Vx(t.baseURL,t.url,t.allowAbsoluteUrls),e.params,e.paramsSerializer),l&&r.set("Authorization","Basic "+btoa((l.username||"")+":"+(l.password?unescape(encodeURIComponent(l.password)):""))),xe.isFormData(n)){if(Qn.hasStandardBrowserEnv||Qn.hasStandardBrowserWebWorkerEnv)r.setContentType(void 0);else if(xe.isFunction(n.getHeaders)){const u=n.getHeaders(),c=["content-type","content-length"];Object.entries(u).forEach(([d,f])=>{c.includes(d.toLowerCase())&&r.set(d,f)})}}if(Qn.hasStandardBrowserEnv&&(o&&xe.isFunction(o)&&(o=o(t)),o||o!==!1&&Iee(t.url))){const u=a&&s&&_ee.read(s);u&&r.set(a,u)}return t},Aee=typeof XMLHttpRequest<"u",Lee=Aee&&function(e){return new Promise(function(n,o){const a=zx(e);let s=a.data;const r=wo.from(a.headers).normalize();let{responseType:l,onUploadProgress:u,onDownloadProgress:c}=a,d,f,v,g,p;function h(){g&&g(),p&&p(),a.cancelToken&&a.cancelToken.unsubscribe(d),a.signal&&a.signal.removeEventListener("abort",d)}let m=new XMLHttpRequest;m.open(a.method.toUpperCase(),a.url,!0),m.timeout=a.timeout;function b(){if(!m)return;const y=wo.from("getAllResponseHeaders"in m&&m.getAllResponseHeaders()),C={data:!l||l==="text"||l==="json"?m.responseText:m.response,status:m.status,statusText:m.statusText,headers:y,config:e,request:m};Fx(function($){n($),h()},function($){o($),h()},C),m=null}"onloadend"in m?m.onloadend=b:m.onreadystatechange=function(){!m||m.readyState!==4||m.status===0&&!(m.responseURL&&m.responseURL.indexOf("file:")===0)||setTimeout(b)},m.onabort=function(){m&&(o(new At("Request aborted",At.ECONNABORTED,e,m)),m=null)},m.onerror=function(S){const C=S&&S.message?S.message:"Network Error",E=new At(C,At.ERR_NETWORK,e,m);E.event=S||null,o(E),m=null},m.ontimeout=function(){let S=a.timeout?"timeout of "+a.timeout+"ms exceeded":"timeout exceeded";const C=a.transitional||hg;a.timeoutErrorMessage&&(S=a.timeoutErrorMessage),o(new At(S,C.clarifyTimeoutError?At.ETIMEDOUT:At.ECONNABORTED,e,m)),m=null},s===void 0&&r.setContentType(null),"setRequestHeader"in m&&xe.forEach(r.toJSON(),function(S,C){m.setRequestHeader(C,S)}),xe.isUndefined(a.withCredentials)||(m.withCredentials=!!a.withCredentials),l&&l!=="json"&&(m.responseType=a.responseType),c&&([v,p]=xd(c,!0),m.addEventListener("progress",v)),u&&m.upload&&([f,g]=xd(u),m.upload.addEventListener("progress",f),m.upload.addEventListener("loadend",g)),(a.cancelToken||a.signal)&&(d=y=>{m&&(o(!y||y.type?new Nu(null,e,m):y),m.abort(),m=null)},a.cancelToken&&a.cancelToken.subscribe(d),a.signal&&(a.signal.aborted?d():a.signal.addEventListener("abort",d)));const k=Oee(a.url);if(k&&Qn.protocols.indexOf(k)===-1){o(new At("Unsupported protocol "+k+":",At.ERR_BAD_REQUEST,e));return}m.send(s||null)})},Dee=(e,t)=>{const{length:n}=e=e?e.filter(Boolean):[];if(t||n){let o=new AbortController,a;const s=function(c){if(!a){a=!0,l();const d=c instanceof Error?c:this.reason;o.abort(d instanceof At?d:new Nu(d instanceof Error?d.message:d))}};let r=t&&setTimeout(()=>{r=null,s(new At(`timeout of ${t}ms exceeded`,At.ETIMEDOUT))},t);const l=()=>{e&&(r&&clearTimeout(r),r=null,e.forEach(c=>{c.unsubscribe?c.unsubscribe(s):c.removeEventListener("abort",s)}),e=null)};e.forEach(c=>c.addEventListener("abort",s));const{signal:u}=o;return u.unsubscribe=()=>xe.asap(l),u}},Bee=function*(e,t){let n=e.byteLength;if(n{const a=Fee(e,t);let s=0,r,l=u=>{r||(r=!0,o&&o(u))};return new ReadableStream({async pull(u){try{const{done:c,value:d}=await a.next();if(c){l(),u.close();return}let f=d.byteLength;if(n){let v=s+=f;n(v)}u.enqueue(new Uint8Array(d))}catch(c){throw l(c),c}},cancel(u){return l(u),a.return()}},{highWaterMark:2})},Sw=64*1024,{isFunction:sc}=xe,zee=(({Request:e,Response:t})=>({Request:e,Response:t}))(xe.global),{ReadableStream:Cw,TextEncoder:kw}=xe.global,Ew=(e,...t)=>{try{return!!e(...t)}catch{return!1}},Hee=e=>{e=xe.merge.call({skipUndefined:!0},zee,e);const{fetch:t,Request:n,Response:o}=e,a=t?sc(t):typeof fetch=="function",s=sc(n),r=sc(o);if(!a)return!1;const l=a&&sc(Cw),u=a&&(typeof kw=="function"?(p=>h=>p.encode(h))(new kw):async p=>new Uint8Array(await new n(p).arrayBuffer())),c=s&&l&&Ew(()=>{let p=!1;const h=new n(Qn.origin,{body:new Cw,method:"POST",get duplex(){return p=!0,"half"}}).headers.has("Content-Type");return p&&!h}),d=r&&l&&Ew(()=>xe.isReadableStream(new o("").body)),f={stream:d&&(p=>p.body)};a&&["text","arrayBuffer","blob","formData","stream"].forEach(p=>{!f[p]&&(f[p]=(h,m)=>{let b=h&&h[p];if(b)return b.call(h);throw new At(`Response type '${p}' is not supported`,At.ERR_NOT_SUPPORT,m)})});const v=async p=>{if(p==null)return 0;if(xe.isBlob(p))return p.size;if(xe.isSpecCompliantForm(p))return(await new n(Qn.origin,{method:"POST",body:p}).arrayBuffer()).byteLength;if(xe.isArrayBufferView(p)||xe.isArrayBuffer(p))return p.byteLength;if(xe.isURLSearchParams(p)&&(p=p+""),xe.isString(p))return(await u(p)).byteLength},g=async(p,h)=>{const m=xe.toFiniteNumber(p.getContentLength());return m??v(h)};return async p=>{let{url:h,method:m,data:b,signal:k,cancelToken:y,timeout:S,onDownloadProgress:C,onUploadProgress:E,responseType:$,headers:O,withCredentials:N="same-origin",fetchOptions:R}=zx(p),A=t||fetch;$=$?($+"").toLowerCase():"text";let M=Dee([k,y&&y.toAbortSignal()],S),z=null;const H=M&&M.unsubscribe&&(()=>{M.unsubscribe()});let U;try{if(E&&c&&m!=="get"&&m!=="head"&&(U=await g(O,b))!==0){let F=new n(h,{method:"POST",body:b,duplex:"half"}),q;if(xe.isFormData(b)&&(q=F.headers.get("content-type"))&&O.setContentType(q),F.body){const[j,X]=gw(U,xd(bw(E)));b=ww(F.body,Sw,j,X)}}xe.isString(N)||(N=N?"include":"omit");const W=s&&"credentials"in n.prototype,_={...R,signal:M,method:m.toUpperCase(),headers:O.normalize().toJSON(),body:b,duplex:"half",credentials:W?N:void 0};z=s&&new n(h,_);let I=await(s?A(z,R):A(h,_));const L=d&&($==="stream"||$==="response");if(d&&(C||L&&H)){const F={};["status","statusText","headers"].forEach(Q=>{F[Q]=I[Q]});const q=xe.toFiniteNumber(I.headers.get("content-length")),[j,X]=C&&gw(q,xd(bw(C),!0))||[];I=new o(ww(I.body,Sw,j,()=>{X&&X(),H&&H()}),F)}$=$||"text";let D=await f[xe.findKey(f,$)||"text"](I,p);return!L&&H&&H(),await new Promise((F,q)=>{Fx(F,q,{data:D,headers:wo.from(I.headers),status:I.status,statusText:I.statusText,config:p,request:z})})}catch(W){throw H&&H(),W&&W.name==="TypeError"&&/Load failed|fetch/i.test(W.message)?Object.assign(new At("Network Error",At.ERR_NETWORK,p,z,W&&W.response),{cause:W.cause||W}):At.from(W,W&&W.code,p,z,W&&W.response)}}},Kee=new Map,Hx=e=>{let t=e&&e.env||{};const{fetch:n,Request:o,Response:a}=t,s=[o,a,n];let r=s.length,l=r,u,c,d=Kee;for(;l--;)u=s[l],c=d.get(u),c===void 0&&d.set(u,c=l?new Map:Hee(t)),d=c;return c};Hx();const mg={http:ree,xhr:Lee,fetch:{get:Hx}};xe.forEach(mg,(e,t)=>{if(e){try{Object.defineProperty(e,"name",{value:t})}catch{}Object.defineProperty(e,"adapterName",{value:t})}});const xw=e=>`- ${e}`,Wee=e=>xe.isFunction(e)||e===null||e===!1;function jee(e,t){e=xe.isArray(e)?e:[e];const{length:n}=e;let o,a;const s={};for(let r=0;r`adapter ${u} `+(c===!1?"is not supported by the environment":"is not available in the build"));let l=n?r.length>1?`since : `+r.map(xw).join(` `):" "+xw(r[0]):"as no adapter specified";throw new At("There is no suitable adapter to dispatch the request "+l,"ERR_NOT_SUPPORT")}return a}const Kx={getAdapter:jee,adapters:mg};function kp(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new Nu(null,e)}function Tw(e){return kp(e),e.headers=wo.from(e.headers),e.data=Cp.call(e,e.transformRequest),["post","put","patch"].indexOf(e.method)!==-1&&e.headers.setContentType("application/x-www-form-urlencoded",!1),Kx.getAdapter(e.adapter||Ru.adapter,e)(e).then(function(o){return kp(e),o.data=Cp.call(e,e.transformResponse,o),o.headers=wo.from(o.headers),o},function(o){return Bx(o)||(kp(e),o&&o.response&&(o.response.data=Cp.call(e,e.transformResponse,o.response),o.response.headers=wo.from(o.response.headers))),Promise.reject(o)})}const Wx="1.13.6",Cf={};["object","boolean","number","function","string","symbol"].forEach((e,t)=>{Cf[e]=function(o){return typeof o===e||"a"+(t<1?"n ":" ")+e}});const $w={};Cf.transitional=function(t,n,o){function a(s,r){return"[Axios v"+Wx+"] Transitional option '"+s+"'"+r+(o?". "+o:"")}return(s,r,l)=>{if(t===!1)throw new At(a(r," has been removed"+(n?" in "+n:"")),At.ERR_DEPRECATED);return n&&!$w[r]&&($w[r]=!0,console.warn(a(r," has been deprecated since v"+n+" and will be removed in the near future"))),t?t(s,r,l):!0}};Cf.spelling=function(t){return(n,o)=>(console.warn(`${o} is likely a misspelling of ${t}`),!0)};function Uee(e,t,n){if(typeof e!="object")throw new At("options must be an object",At.ERR_BAD_OPTION_VALUE);const o=Object.keys(e);let a=o.length;for(;a-- >0;){const s=o[a],r=t[s];if(r){const l=e[s],u=l===void 0||r(l,s,e);if(u!==!0)throw new At("option "+s+" must be "+u,At.ERR_BAD_OPTION_VALUE);continue}if(n!==!0)throw new At("Unknown option "+s,At.ERR_BAD_OPTION)}}const Vc={assertOptions:Uee,validators:Cf},Ao=Vc.validators;let vr=class{constructor(t){this.defaults=t||{},this.interceptors={request:new vw,response:new vw}}async request(t,n){try{return await this._request(t,n)}catch(o){if(o instanceof Error){let a={};Error.captureStackTrace?Error.captureStackTrace(a):a=new Error;const s=a.stack?a.stack.replace(/^.+\n/,""):"";try{o.stack?s&&!String(o.stack).endsWith(s.replace(/^.+\n.+\n/,""))&&(o.stack+=` -`+s):o.stack=s}catch{}}throw o}}_request(t,n){typeof t=="string"?(n=n||{},n.url=t):n=t||{},n=$r(this.defaults,n);const{transitional:o,paramsSerializer:a,headers:s}=n;o!==void 0&&Vc.assertOptions(o,{silentJSONParsing:Ao.transitional(Ao.boolean),forcedJSONParsing:Ao.transitional(Ao.boolean),clarifyTimeoutError:Ao.transitional(Ao.boolean),legacyInterceptorReqResOrdering:Ao.transitional(Ao.boolean)},!1),a!=null&&(xe.isFunction(a)?n.paramsSerializer={serialize:a}:Vc.assertOptions(a,{encode:Ao.function,serialize:Ao.function},!0)),n.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?n.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:n.allowAbsoluteUrls=!0),Vc.assertOptions(n,{baseUrl:Ao.spelling("baseURL"),withXsrfToken:Ao.spelling("withXSRFToken")},!0),n.method=(n.method||this.defaults.method||"get").toLowerCase();let r=s&&xe.merge(s.common,s[n.method]);s&&xe.forEach(["delete","get","head","post","put","patch","common"],p=>{delete s[p]}),n.headers=wo.concat(r,s);const l=[];let u=!0;this.interceptors.request.forEach(function(h){if(typeof h.runWhen=="function"&&h.runWhen(n)===!1)return;u=u&&h.synchronous;const m=n.transitional||hg;m&&m.legacyInterceptorReqResOrdering?l.unshift(h.fulfilled,h.rejected):l.push(h.fulfilled,h.rejected)});const c=[];this.interceptors.response.forEach(function(h){c.push(h.fulfilled,h.rejected)});let d,f=0,v;if(!u){const p=[Tw.bind(this),void 0];for(p.unshift(...l),p.push(...c),v=p.length,d=Promise.resolve(n);f{if(!o._listeners)return;let s=o._listeners.length;for(;s-- >0;)o._listeners[s](a);o._listeners=null}),this.promise.then=a=>{let s;const r=new Promise(l=>{o.subscribe(l),s=l}).then(a);return r.cancel=function(){o.unsubscribe(s)},r},t(function(s,r,l){o.reason||(o.reason=new Nu(s,r,l),n(o.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const n=this._listeners.indexOf(t);n!==-1&&this._listeners.splice(n,1)}toAbortSignal(){const t=new AbortController,n=o=>{t.abort(o)};return this.subscribe(n),t.signal.unsubscribe=()=>this.unsubscribe(n),t.signal}static source(){let t;return{token:new jx(function(a){t=a}),cancel:t}}};function Yee(e){return function(n){return e.apply(null,n)}}function Gee(e){return xe.isObject(e)&&e.isAxiosError===!0}const Gh={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(Gh).forEach(([e,t])=>{Gh[t]=e});function Ux(e){const t=new vr(e),n=xx(vr.prototype.request,t);return xe.extend(n,vr.prototype,t,{allOwnKeys:!0}),xe.extend(n,t,null,{allOwnKeys:!0}),n.create=function(a){return Ux($r(e,a))},n}const On=Ux(Ru);On.Axios=vr;On.CanceledError=Nu;On.CancelToken=qee;On.isCancel=Bx;On.VERSION=Wx;On.toFormData=Sf;On.AxiosError=At;On.Cancel=On.CanceledError;On.all=function(t){return Promise.all(t)};On.spread=Yee;On.isAxiosError=Gee;On.mergeConfig=$r;On.AxiosHeaders=wo;On.formToJSON=e=>Dx(xe.isHTMLForm(e)?new FormData(e):e);On.getAdapter=Kx.getAdapter;On.HttpStatusCode=Gh;On.default=On;const{Axios:zte,AxiosError:Xee,CanceledError:Hte,isCancel:Kte,CancelToken:Wte,VERSION:jte,all:Ute,Cancel:qte,isAxiosError:Yte,spread:Gte,toFormData:Xte,AxiosHeaders:Jte,HttpStatusCode:Zte,formToJSON:Qte,getAdapter:ene,mergeConfig:tne}=On;function Jee(e){if(e instanceof Xee){const t=e.response?.data;if(t&&typeof t=="object"){if("error"in t&&t.error)return String(t.error);if("message"in t&&t.message)return String(t.message)}return typeof t=="string"&&t.trim()?t:e.message||"请求失败"}return e instanceof Error?e.message:"请求失败"}function Zee(){const e=On.create({withCredentials:!0,timeout:3e4,headers:{"X-Requested-With":"XMLHttpRequest"}});return e.interceptors.request.use(t=>t),e.interceptors.response.use(t=>t,t=>Promise.reject(new Error(Jee(t)))),e}const Qee=Zee();async function kf(e){return(await Qee.request(e)).data}function Zt(e,t){return kf({url:e,method:"GET",...t})}function Qt(e,t,n){return kf({url:e,method:"POST",data:t,...n})}function Ef(e,t,n){return kf({url:e,method:"PUT",data:t,...n})}function cn(e,t){return kf({url:e,method:"DELETE",...t})}const ete=Zt,nne=Qt;async function Ge(e){const t=await e;if(!t.success)throw new Error(t.message||"请求失败");return t.data}function tte(){const e=typeof window>"u"?"":window.localStorage.getItem("uid")||"",t=Number(e);if(!Number.isFinite(t)||t<=0)throw new Error("未获取到用户ID");return t}function nte(e){return`app_column_permissions:${String(e)}`}async function ote(){const e=tte(),t=nte(e);try{const o=JSON.parse(window.localStorage.getItem(t)||"null");if(Array.isArray(o))return o.map(a=>String(a.column_key||"").trim().toLowerCase()).filter(Boolean)}catch{}const n=await ete(`/api/admin/user/${encodeURIComponent(String(e))}/column-permissions`,{params:{menu_type:"app"}});if(!n.success)throw new Error(n.error||"获取菜单权限失败");try{window.localStorage.setItem(t,JSON.stringify(n.items||[]))}catch{}return(n.items||[]).map(o=>String(o.column_key||"").trim().toLowerCase()).filter(Boolean)}let Xh,Ow=!1;function qx(){return Xh=window.pywebview?.api,Xh}function ate(){Ow||typeof window>"u"||!window.addEventListener||(Ow=!0,window.addEventListener("pywebviewready",()=>{qx()}))}ate();function ste(){return qx()||Xh}const Yi=Mt({});let Rw=!1;function rte(e){return Number.isFinite(e)?Math.max(0,Math.min(100,Math.round(e))):0}function lte(){return Date.now()}function Yr(e){const t=Yi[e.id],n=lte();Yi[e.id]={id:e.id,filename:e.filename||t?.filename||"下载文件",status:e.status||t?.status||"running",path:e.path??t?.path,downloaded:Number(e.downloaded??t?.downloaded??0),total:Number(e.total??t?.total??0),percent:rte(Number(e.percent??t?.percent??0)),error:e.error??t?.error,createdAt:t?.createdAt||n,updatedAt:n}}function ite(e){const t=e.detail;t?.id&&Yr({id:t.id,status:t.status,path:t.path,downloaded:t.downloaded,total:t.total,percent:t.percent,error:t.error})}function Yx(){Rw||typeof window>"u"||(Rw=!0,window.addEventListener("pywebview-download-progress",ite))}function ute(){return Yx(),{items:w(()=>Object.values(Yi).filter(t=>t.status!=="cancelled").sort((t,n)=>n.createdAt-t.createdAt)),clearDownloadProgress:gg}}function gg(e){delete Yi[e]}function cte(e){const t=e.replace(/[^a-zA-Z0-9._-]+/g,"-").slice(0,60)||"download";return`download:${Date.now()}:${Math.random().toString(16).slice(2)}:${t}`}async function one(e,t,n=cte(t)){Yx();const o=ste();if(!o?.save_file_from_url_new)return Yr({id:n,filename:t,status:"failed",downloaded:0,total:0,percent:0,error:"当前客户端未提供下载能力"}),{success:!1,error:"当前客户端未提供下载能力"};Yr({id:n,filename:t,status:"selecting",downloaded:0,total:0,percent:0});const a=o.save_file_from_url_with_progress?await o.save_file_from_url_with_progress(e,t,n):await o.save_file_from_url_new(e,t);if(a.success){const s=Yi[n];Yr({id:n,filename:t,status:"success",path:a.path,downloaded:s?.downloaded||s?.total||0,total:s?.total||s?.downloaded||0,percent:100})}else a.error==="用户取消"?(Yr({id:n,filename:t,status:"cancelled",downloaded:0,total:0,percent:0}),gg(n)):Yr({id:n,filename:t,status:"failed",downloaded:0,total:0,percent:0,error:a.error||"下载失败"});return a}function Nw(e){const t=Number(e||0);return!Number.isFinite(t)||t<=0?"未知大小":t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:t<1024*1024*1024?`${(t/1024/1024).toFixed(1)} MB`:`${(t/1024/1024/1024).toFixed(2)} GB`}function dte(e){return e.status==="selecting"?"等待选择保存位置":e.status==="success"?"下载完成":e.status==="failed"?e.error||"下载失败":e.total>0?"正在下载,请等待完成后再打开":"正在下载,正在获取文件大小"}const fte={key:0,class:"download-progress-panel"},pte={class:"download-progress-head"},hte=["title"],vte=["onClick"],mte={class:"download-progress-meta"},gte={class:"download-progress-track"},bte={class:"download-progress-size"},yte=se({__name:"DownloadProgressPanel",setup(e){const{items:t}=ute(),n=w(()=>t.value.slice(0,5));return(o,a)=>n.value.length?(x(),B("div",fte,[a[0]||(a[0]=V("div",{class:"download-progress-title"},"下载进度",-1)),(x(!0),B(Fe,null,gt(n.value,s=>(x(),B("div",{key:s.id,class:T(["download-progress-item",s.status])},[V("div",pte,[V("span",{class:"download-progress-name",title:s.filename},we(s.filename),9,hte),V("button",{type:"button",class:"download-progress-close",onClick:r=>i(gg)(s.id)},"×",8,vte)]),V("div",mte,[V("span",null,we(i(dte)(s)),1),V("span",null,we(s.percent)+"%",1)]),V("div",gte,[V("div",{class:"download-progress-bar",style:Ke({width:`${s.percent}%`})},null,4)]),V("div",bte,we(i(Nw)(s.downloaded))+" / "+we(i(Nw)(s.total)),1)],2))),128))])):te("",!0)}}),wte=dg(yte,[["__scopeId","data-v-5a9fa6a2"]]),Ste={class:"top-bar"},Cte={class:"nav-sections","aria-label":"顶部功能导航"},kte={class:"nav-section-title"},Ete={class:"nav-section-items"},xte=["href"],Tte={class:"top-right"},$te=se({__name:"BrandTopBar",props:{active:{}},setup(e){const n=e.active,o=P(null),a=[{columnKey:"brand_front_tools",label:"前端工具",items:[{key:"collect-data",label:"采集数据",href:"/new_web_source/collect-data.html"},{key:"variant",label:"变体分析"},{key:"brand",label:"品牌检测",href:"/brand"},{key:"appearance-patent",label:"外观专利检测",href:"/new_web_source/appearance-patent.html"},{key:"similar-asin",label:"货源查询",href:"/new_web_source/similar-asin.html"},{key:"dedupe",label:"数据去重",href:"/new_web_source/dedupe.html"},{key:"split",label:"数据拆分",href:"/new_web_source/split.html"},{key:"convert",label:"格式转换",href:"/new_web_source/convert.html"}]},{columnKey:"brand_operation_tools",label:"运营工具",items:[{key:"delete-brand",label:"删除ASIN",href:"/new_web_source/delete-brand.html"},{key:"product-risk",label:"商品风险解决",href:"/new_web_source/product-risk.html"},{key:"shop-match",label:"定时匹配",href:"/new_web_source/shop-match.html"},{key:"pricing",label:"跟价",href:"/new_web_source/price-track.html"},{key:"patrol-delete",label:"巡店删除",href:"/new_web_source/patrol-delete.html"},{key:"query-asin",label:"查询ASIN",href:"/new_web_source/query-asin.html"},{key:"withdraw",label:"取款"},{key:"shop-status",label:"店铺状态查询"}]},{columnKey:"brand_logistics_tools",label:"后勤工具",items:[{key:"purchase",label:"采购"},{key:"erp",label:"ERP"}]}],s=w(()=>{if(o.value===null)return a;const r=new Set(o.value);return a.filter(l=>r.has(l.columnKey))});return ht(async()=>{try{o.value=await ote()}catch{o.value=null}}),(r,l)=>(x(),B("header",Ste,[l[0]||(l[0]=V("div",{class:"logo-area"},[V("span",{class:"app-name"},"数富AI-亚马逊"),V("a",{href:"/home",class:"btn-home"},"返回首页")],-1)),V("nav",Cte,[(x(!0),B(Fe,null,gt(s.value,u=>(x(),B("section",{key:u.columnKey,class:"nav-section"},[V("div",kte,we(u.label),1),V("div",Ete,[(x(!0),B(Fe,null,gt(u.items,c=>(x(),B(Fe,{key:c.key},[c.href?(x(),B("a",{key:0,href:c.href,class:T(["nav-item",{active:i(n)===c.key}])},we(c.label),11,xte)):(x(),B("span",{key:1,class:T(["nav-item disabled",{active:i(n)===c.key}])},we(c.label),3))],64))),128))])]))),128))]),V("div",Tte,[Y(gQ)]),Y(wte)]))}}),ane=dg($te,[["__scopeId","data-v-74abee09"]]),Ote=1e4,Rte=6e4,Nte=5e3,Ite=3e4;function sne(){return typeof document<"u"&&document.visibilityState!=="visible"?Rte:Ote}function _te(){return typeof document<"u"&&document.hidden?Ite:Nte}const je="/newApi/api",Iw=new Map,Ep=new Map;function Ze(){const e=typeof window>"u"?"":window.localStorage.getItem("uid")||"",t=Number(e);if(!Number.isFinite(t)||t<=0)throw new Error("未获取到用户ID");return t}function Pte(e){return Array.from(new Set((e||[]).map(t=>Number(t)).filter(t=>Number.isFinite(t)&&t>0))).sort((t,n)=>t-n)}function Mte(e,t){return`${e}::${t.join(",")}`}async function ys(e,t,n={}){const o=Pte(t);if(!o.length)return{items:[],missingTaskIds:[]};const a=Mte(e,o),s=Date.now(),r=Iw.get(a);if(!n.force&&r&&r.expiresAt>s)return r.data;const l=Ep.get(a);if(!n.force&&l)return await l;const u=Ge(Qt(e,{taskIds:o})).then(c=>(Iw.set(a,{data:c,expiresAt:Date.now()+_te()}),c)).finally(()=>{Ep.delete(a)});return Ep.set(a,u),u}function rne(e){return Ge(Zt(`${je}/files/excel-info`,{params:{fileKey:e}}))}function lne(e){return Ge(Qt(`${je}/dedupe/run`,{...e,user_id:Ze()}))}function ine(){return Ge(Zt(`${je}/dedupe/history`,{params:{user_id:Ze()}}))}function une(e){return Ge(cn(`${je}/dedupe/history/${e}`,{params:{user_id:Ze()}}))}function cne(e){return Wo(`/dedupe/results/${e}/download`)}function dne(e){return Ge(Qt(`${je}/split/run`,{...e,user_id:Ze()}))}function fne(){return Ge(Zt(`${je}/split/history`,{params:{user_id:Ze()}}))}function pne(e){return Ge(cn(`${je}/split/history/${e}`,{params:{user_id:Ze()}}))}function hne(e){return Wo(`/split/results/${e}/download`)}function vne(){return Ge(Zt(`${je}/convert/templates`))}function mne(e){return Ge(Qt(`${je}/convert/run`,{...e,user_id:Ze()}))}function gne(){return Ge(Zt(`${je}/convert/history`,{params:{user_id:Ze()}}))}function bne(e){return Ge(cn(`${je}/convert/history/${e}`,{params:{user_id:Ze()}}))}function yne(e){return Wo(`/convert/results/${e}/download`)}function wne(e){return Ge(Qt(`${je}/delete-brand/run`,{...e,user_id:Ze()},{timeout:18e4}))}function Sne(){return Ge(Zt(`${je}/delete-brand/history`,{params:{user_id:Ze()}}))}function Cne(e){return Ge(cn(`${je}/delete-brand/history/${e}`,{params:{user_id:Ze()}}))}function kne(e){return Wo(`/delete-brand/tasks/${e}/download`)}function Ene(e){return Wo(`/delete-brand/results/${e}/download`)}function xne(){return Ge(Zt(`${je}/product-risk-resolve/candidates`,{params:{user_id:Ze()}}))}function Tne(e){return Ge(Qt(`${je}/product-risk-resolve/candidates`,{user_id:Ze(),shop_name:e}))}function $ne(e){return Ge(cn(`${je}/product-risk-resolve/candidates/${e}`,{params:{user_id:Ze()}}))}function One(){return Ge(Zt(`${je}/product-risk-resolve/country-preference`,{params:{user_id:Ze()}}))}function Rne(e){return Ge(Ef(`${je}/product-risk-resolve/country-preference`,{user_id:Ze(),country_codes:e}))}function Nne(e){return Ge(Qt(`${je}/product-risk-resolve/match-shops`,{user_id:Ze(),shop_names:e}))}function Ine(){return Ge(Zt(`${je}/product-risk-resolve/dashboard`,{params:{user_id:Ze()}}))}function _ne(){return Ge(Zt(`${je}/product-risk-resolve/history`,{params:{user_id:Ze()}}))}function Pne(e){return Ge(cn(`${je}/product-risk-resolve/history/${e}`,{params:{user_id:Ze()}}))}function Mne(e){return Ge(Qt(`${je}/product-risk-resolve/tasks`,{user_id:Ze(),items:e}))}function Ane(e){return Ge(cn(`${je}/product-risk-resolve/tasks/${e}`,{params:{user_id:Ze()}}))}function Lne(e){return Ge(cn(`${je}/product-risk-resolve/pending-shop-result`,{params:{user_id:Ze(),shop_name:e}}))}function Dne(e){return Wo(`/product-risk-resolve/results/${e}/download`)}function Bne(){return Ge(Zt(`${je}/shop-match/candidates`,{params:{user_id:Ze()}}))}function Fne(e){return Ge(Qt(`${je}/shop-match/candidates`,{user_id:Ze(),shop_name:e}))}function Vne(e){return Ge(cn(`${je}/shop-match/candidates/${e}`,{params:{user_id:Ze()}}))}function zne(){return Ge(Zt(`${je}/shop-match/country-preference`,{params:{user_id:Ze()}}))}function Hne(e){return Ge(Ef(`${je}/shop-match/country-preference`,{user_id:Ze(),country_codes:e}))}function Kne(e){return Ge(Qt(`${je}/shop-match/match-shops`,{user_id:Ze(),shop_names:e}))}function Wne(){return Ge(Zt(`${je}/shop-match/dashboard`,{params:{user_id:Ze()}}))}function jne(){return Ge(Zt(`${je}/shop-match/history`,{params:{user_id:Ze()}}))}function Une(e){return Ge(cn(`${je}/shop-match/history/${e}`,{params:{user_id:Ze()}}))}function qne(e,t,n){return Ge(Qt(`${je}/shop-match/tasks`,{user_id:Ze(),items:e,country_codes:t,schedule_times:n}))}function Yne(e){return Ge(cn(`${je}/shop-match/tasks/${e}`,{params:{user_id:Ze()}}))}function Gne(e,t){return Ge(Qt(`${je}/shop-match/tasks/${e}/activate?user_id=${encodeURIComponent(String(Ze()))}&stage_index=${encodeURIComponent(String(t))}`,void 0))}function Xne(e){return Wo(`/shop-match/results/${e}/download`)}function Jne(){return Ge(Zt(`${je}/patrol-delete/candidates`,{params:{user_id:Ze()}}))}function Zne(e){return Ge(Qt(`${je}/patrol-delete/candidates`,{user_id:Ze(),shop_name:e}))}function Qne(e){return Ge(cn(`${je}/patrol-delete/candidates/${e}`,{params:{user_id:Ze()}}))}function eoe(){return Ge(Zt(`${je}/patrol-delete/conditions`,{params:{user_id:Ze()}}))}function toe(e){return Ge(Qt(`${je}/patrol-delete/conditions`,{user_id:Ze(),condition_text:e}))}function noe(e){return Ge(cn(`${je}/patrol-delete/conditions/${e}`,{params:{user_id:Ze()}}))}function ooe(e){return Ge(Qt(`${je}/patrol-delete/match-shops`,{user_id:Ze(),shop_names:e}))}function aoe(){return Ge(Zt(`${je}/patrol-delete/dashboard`,{params:{user_id:Ze()}}))}function soe(){return Ge(Zt(`${je}/patrol-delete/history`,{params:{user_id:Ze()}}))}function roe(e){return ys(`${je}/patrol-delete/tasks/progress/batch`,e)}function loe(e){return Ge(Qt(`${je}/patrol-delete/tasks`,{user_id:Ze(),items:e}))}function ioe(e,t){return Ge(Qt(`${je}/patrol-delete/tasks/${e}/result`,t))}function uoe(e){return Wo(`/patrol-delete/results/${e}/download`)}function coe(e){return Ge(cn(`${je}/patrol-delete/tasks/${e}`,{params:{user_id:Ze()}}))}function doe(e){return Ge(cn(`${je}/patrol-delete/history/${e}`,{params:{user_id:Ze()}}))}function foe(){return Ge(Zt(`${je}/query-asin/candidates`,{params:{user_id:Ze()}}))}function poe(e){return Ge(Qt(`${je}/query-asin/candidates`,{user_id:Ze(),shop_name:e}))}function hoe(e){return Ge(cn(`${je}/query-asin/candidates/${e}`,{params:{user_id:Ze()}}))}function voe(e){return Ge(Qt(`${je}/query-asin/match-shops`,{user_id:Ze(),shop_names:e}))}function moe(){return Ge(Zt(`${je}/query-asin/dashboard`,{params:{user_id:Ze()}}))}function goe(){return Ge(Zt(`${je}/query-asin/history`,{params:{user_id:Ze()}}))}function boe(e){return ys(`${je}/query-asin/tasks/progress/batch`,e)}function yoe(e){return Ge(Qt(`${je}/query-asin/tasks`,{user_id:Ze(),items:e}))}function woe(e,t){return Ge(Qt(`${je}/query-asin/tasks/${e}/result`,t))}function Soe(e){return Wo(`/query-asin/results/${e}/download`)}function Coe(e){return Ge(cn(`${je}/query-asin/tasks/${e}`,{params:{user_id:Ze()}}))}function koe(e){return Ge(cn(`${je}/query-asin/history/${e}`,{params:{user_id:Ze()}}))}function Eoe(e,t,n){return Ge(Qt(`${je}/appearance-patent/parse`,{user_id:Ze(),files:e,ai_prompt:t,api_key:n}))}function xoe(e){return Ge(Zt(`${je}/appearance-patent/tasks/${e}/queue-payload`,{params:{user_id:Ze()}}))}function Toe(){return Ge(Zt(`${je}/appearance-patent/dashboard`,{params:{user_id:Ze()}}))}function $oe(){return Ge(Zt(`${je}/appearance-patent/history`,{params:{user_id:Ze(),limit:50}}))}function Ooe(e,t={}){return ys(`${je}/appearance-patent/tasks/progress/batch`,e,t)}function Roe(e){return Ge(Qt(`${je}/appearance-patent/tasks/${e}/activate?user_id=${encodeURIComponent(String(Ze()))}`,void 0))}function Noe(e){return Ge(cn(`${je}/appearance-patent/tasks/${e}`,{params:{user_id:Ze()}}))}function Ioe(e){return Ge(cn(`${je}/appearance-patent/history/${e}`,{params:{user_id:Ze()}}))}function _oe(e){return Wo(`/appearance-patent/results/${e}/download`)}function Poe(e,t){return Ge(Qt(`${je}/similar-asin/parse`,{user_id:Ze(),files:e,api_key:t}))}function Moe(){return Ge(Zt(`${je}/similar-asin/dashboard`,{params:{user_id:Ze()}}))}function Aoe(){return Ge(Zt(`${je}/similar-asin/history`,{params:{user_id:Ze(),limit:50}}))}function Loe(e,t={}){return ys(`${je}/similar-asin/tasks/progress/batch`,e,t)}function Doe(e){return Ge(Qt(`${je}/similar-asin/tasks/${e}/activate?user_id=${encodeURIComponent(String(Ze()))}`,void 0))}function Boe(e){return Ge(cn(`${je}/similar-asin/tasks/${e}`,{params:{user_id:Ze()}}))}function Foe(e){return Ge(cn(`${je}/similar-asin/history/${e}`,{params:{user_id:Ze()}}))}function Voe(e){return Wo(`/similar-asin/results/${e}/download`)}function zoe(){return Ge(Zt(`${je}/price-track/candidates?user_id=${encodeURIComponent(String(Ze()))}`))}function Hoe(e){return Ge(Qt(`${je}/price-track/candidates`,{userId:Ze(),shopName:e}))}function Koe(e){return Ge(cn(`${je}/price-track/candidates/${e}?user_id=${encodeURIComponent(String(Ze()))}`))}function Woe(){return Ge(Zt(`${je}/price-track/country-preference?user_id=${encodeURIComponent(String(Ze()))}`))}function joe(e){return Ge(Ef(`${je}/price-track/country-preference`,{userId:Ze(),countryCodes:e}))}function Uoe(e,t){return Ge(Qt(`${je}/price-track/match-shops`,{userId:Ze(),shopNames:e,asinFiles:t?.asinFiles||[],countryCodes:t?.countryCodes||[]}))}function qoe(e){return ys(`${je}/shop-match/tasks/progress/batch`,e)}function Yoe(e){return ys(`${je}/product-risk-resolve/tasks/progress/batch`,e)}function Goe(e){return ys(`${je}/delete-brand/tasks/progress/batch`,e)}function Xoe(){return Ge(Zt(`${je}/price-track/dashboard?user_id=${encodeURIComponent(String(Ze()))}`))}function Joe(){return Ge(Zt(`${je}/price-track/history?user_id=${encodeURIComponent(String(Ze()))}`))}function Zoe(e){return Ge(cn(`${je}/price-track/history/${e}?user_id=${encodeURIComponent(String(Ze()))}`))}function Qoe(e){return Ge(Qt(`${je}/price-track/tasks`,{...e,userId:Ze()}))}function eae(e){return Ge(cn(`${je}/price-track/tasks/${e}?user_id=${encodeURIComponent(String(Ze()))}`))}function tae(e){return Ge(Qt(`${je}/price-track/loop-runs`,{...e,userId:Ze()}))}function nae(e){return Ge(Zt(`${je}/price-track/loop-runs/${e}?user_id=${encodeURIComponent(String(Ze()))}`))}function oae(e){return Ge(Qt(`${je}/price-track/loop-runs/${e}/dispatch-next?user_id=${encodeURIComponent(String(Ze()))}`,void 0))}function aae(e,t){return Ge(Qt(`${je}/price-track/loop-runs/${e}/child-finished?user_id=${encodeURIComponent(String(Ze()))}`,{childTaskId:t}))}function sae(e){return Ge(Qt(`${je}/price-track/loop-runs/${e}/stop?user_id=${encodeURIComponent(String(Ze()))}`,void 0))}function rae(e){return ys(`${je}/price-track/tasks/progress/batch`,e)}function lae(e){return Wo(`/price-track/results/${e}/download`)}function iae(e){return Ge(cn(`${je}/price-track/pending-shop-result?user_id=${encodeURIComponent(String(Ze()))}&shop_name=${encodeURIComponent(e)}`))}function uae(e){return Ge(Qt(`${je}/collect-data/parse`,{...e,user_id:Ze()}))}function cae(e){return Ge(Qt(`${je}/collect-data/tasks/${e}/activate?user_id=${encodeURIComponent(String(Ze()))}`,void 0))}function dae(){return Ge(Zt(`${je}/collect-data/dashboard`,{params:{user_id:Ze()}}))}function fae(e=50){return Ge(Zt(`${je}/collect-data/history`,{params:{user_id:Ze(),limit:e}}))}function pae(e,t={}){return ys(`${je}/collect-data/tasks/progress/batch`,e,t)}function hae(e){return Ge(cn(`${je}/collect-data/tasks/${e}`,{params:{user_id:Ze()}}))}function vae(e){return Ge(cn(`${je}/collect-data/history/${e}`,{params:{user_id:Ze()}}))}function mae(){return Ge(Zt(`${je}/collect-data/country-preference`,{params:{user_id:Ze()}}))}function gae(e){return Ge(Ef(`${je}/collect-data/country-preference`,{user_id:Ze(),country_codes:e}))}function Wo(e){let t=e.startsWith("http://")||e.startsWith("https://")?e:`${je}${e}`;!t.startsWith("http://")&&!t.startsWith("https://")&&typeof window<"u"&&(t=`${window.location.origin}${t}`);const n=t.includes("?")?"&":"?";return`${t}${n}user_id=${encodeURIComponent(String(Ze()))}`}export{$oe as $,mne as A,ane as B,gne as C,bne as D,Wh as E,Fe as F,yne as G,wv as H,dne as I,fne as J,pne as K,hne as L,Ol as M,Ate as N,Ke as O,Goe as P,wne as Q,Ene as R,kne as S,Sne as T,Cne as U,sne as V,Eoe as W,xoe as X,Roe as Y,Toe as Z,dg as _,x as a,Qoe as a$,_oe as a0,Noe as a1,Ioe as a2,Dte as a3,Ooe as a4,Poe as a5,Doe as a6,Moe as a7,Aoe as a8,Voe as a9,Mne as aA,S5 as aB,Bne as aC,Wne as aD,jne as aE,zne as aF,Fne as aG,Vne as aH,Kne as aI,Xne as aJ,Yne as aK,Une as aL,qne as aM,Hne as aN,qoe as aO,Gne as aP,st as aQ,q2 as aR,joe as aS,Woe as aT,zoe as aU,Xoe as aV,Joe as aW,Hoe as aX,Koe as aY,Uoe as aZ,iae as a_,Boe as aa,Foe as ab,Loe as ac,an as ad,eo as ae,J as af,Tq as ag,xq as ah,Je as ai,i as aj,ae as ak,ud as al,Ks as am,Rne as an,One as ao,Lne as ap,Pne as aq,Ane as ar,Ine as as,xne as at,_ne as au,Yoe as av,Tne as aw,$ne as ax,Nne as ay,Dne as az,Y as b,nae as b0,sae as b1,aae as b2,oae as b3,tae as b4,lae as b5,Zoe as b6,eae as b7,rae as b8,Jne as b9,y8 as bA,le as bB,Bt as bC,Mt as bD,gae as bE,mae as bF,uae as bG,cae as bH,dae as bI,fae as bJ,vae as bK,hae as bL,pae as bM,nne as bN,eoe as ba,aoe as bb,soe as bc,Zne as bd,toe as be,noe as bf,Qne as bg,ooe as bh,loe as bi,ioe as bj,uoe as bk,coe as bl,doe as bm,roe as bn,foe as bo,moe as bp,goe as bq,poe as br,hoe as bs,voe as bt,yoe as bu,woe as bv,Soe as bw,Coe as bx,koe as by,boe as bz,B as c,se as d,V as e,te as f,P as g,w as h,ste as i,lne as j,ine as k,une as l,cne as m,T as n,ht as o,rne as p,mO as q,gt as r,one as s,we as t,Lte as u,tS as v,ut as w,Sv as x,wt as y,vne as z}; +`+s):o.stack=s}catch{}}throw o}}_request(t,n){typeof t=="string"?(n=n||{},n.url=t):n=t||{},n=$r(this.defaults,n);const{transitional:o,paramsSerializer:a,headers:s}=n;o!==void 0&&Vc.assertOptions(o,{silentJSONParsing:Ao.transitional(Ao.boolean),forcedJSONParsing:Ao.transitional(Ao.boolean),clarifyTimeoutError:Ao.transitional(Ao.boolean),legacyInterceptorReqResOrdering:Ao.transitional(Ao.boolean)},!1),a!=null&&(xe.isFunction(a)?n.paramsSerializer={serialize:a}:Vc.assertOptions(a,{encode:Ao.function,serialize:Ao.function},!0)),n.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?n.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:n.allowAbsoluteUrls=!0),Vc.assertOptions(n,{baseUrl:Ao.spelling("baseURL"),withXsrfToken:Ao.spelling("withXSRFToken")},!0),n.method=(n.method||this.defaults.method||"get").toLowerCase();let r=s&&xe.merge(s.common,s[n.method]);s&&xe.forEach(["delete","get","head","post","put","patch","common"],p=>{delete s[p]}),n.headers=wo.concat(r,s);const l=[];let u=!0;this.interceptors.request.forEach(function(h){if(typeof h.runWhen=="function"&&h.runWhen(n)===!1)return;u=u&&h.synchronous;const m=n.transitional||hg;m&&m.legacyInterceptorReqResOrdering?l.unshift(h.fulfilled,h.rejected):l.push(h.fulfilled,h.rejected)});const c=[];this.interceptors.response.forEach(function(h){c.push(h.fulfilled,h.rejected)});let d,f=0,v;if(!u){const p=[Tw.bind(this),void 0];for(p.unshift(...l),p.push(...c),v=p.length,d=Promise.resolve(n);f{if(!o._listeners)return;let s=o._listeners.length;for(;s-- >0;)o._listeners[s](a);o._listeners=null}),this.promise.then=a=>{let s;const r=new Promise(l=>{o.subscribe(l),s=l}).then(a);return r.cancel=function(){o.unsubscribe(s)},r},t(function(s,r,l){o.reason||(o.reason=new Nu(s,r,l),n(o.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const n=this._listeners.indexOf(t);n!==-1&&this._listeners.splice(n,1)}toAbortSignal(){const t=new AbortController,n=o=>{t.abort(o)};return this.subscribe(n),t.signal.unsubscribe=()=>this.unsubscribe(n),t.signal}static source(){let t;return{token:new jx(function(a){t=a}),cancel:t}}};function Yee(e){return function(n){return e.apply(null,n)}}function Gee(e){return xe.isObject(e)&&e.isAxiosError===!0}const Gh={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(Gh).forEach(([e,t])=>{Gh[t]=e});function Ux(e){const t=new vr(e),n=xx(vr.prototype.request,t);return xe.extend(n,vr.prototype,t,{allOwnKeys:!0}),xe.extend(n,t,null,{allOwnKeys:!0}),n.create=function(a){return Ux($r(e,a))},n}const On=Ux(Ru);On.Axios=vr;On.CanceledError=Nu;On.CancelToken=qee;On.isCancel=Bx;On.VERSION=Wx;On.toFormData=Sf;On.AxiosError=At;On.Cancel=On.CanceledError;On.all=function(t){return Promise.all(t)};On.spread=Yee;On.isAxiosError=Gee;On.mergeConfig=$r;On.AxiosHeaders=wo;On.formToJSON=e=>Dx(xe.isHTMLForm(e)?new FormData(e):e);On.getAdapter=Kx.getAdapter;On.HttpStatusCode=Gh;On.default=On;const{Axios:zte,AxiosError:Xee,CanceledError:Hte,isCancel:Kte,CancelToken:Wte,VERSION:jte,all:Ute,Cancel:qte,isAxiosError:Yte,spread:Gte,toFormData:Xte,AxiosHeaders:Jte,HttpStatusCode:Zte,formToJSON:Qte,getAdapter:ene,mergeConfig:tne}=On;function Jee(e){if(e instanceof Xee){const t=e.response?.data;if(t&&typeof t=="object"){if("error"in t&&t.error)return String(t.error);if("message"in t&&t.message)return String(t.message)}return typeof t=="string"&&t.trim()?t:e.message||"请求失败"}return e instanceof Error?e.message:"请求失败"}function Zee(){const e=On.create({withCredentials:!0,timeout:3e4,headers:{"X-Requested-With":"XMLHttpRequest"}});return e.interceptors.request.use(t=>t),e.interceptors.response.use(t=>t,t=>Promise.reject(new Error(Jee(t)))),e}const Qee=Zee();async function kf(e){return(await Qee.request(e)).data}function Zt(e,t){return kf({url:e,method:"GET",...t})}function Qt(e,t,n){return kf({url:e,method:"POST",data:t,...n})}function Ef(e,t,n){return kf({url:e,method:"PUT",data:t,...n})}function cn(e,t){return kf({url:e,method:"DELETE",...t})}const ete=Zt,nne=Qt;async function Ge(e){const t=await e;if(!t.success)throw new Error(t.message||"请求失败");return t.data}function tte(){const e=typeof window>"u"?"":window.localStorage.getItem("uid")||"",t=Number(e);if(!Number.isFinite(t)||t<=0)throw new Error("未获取到用户ID");return t}function nte(e){return`app_column_permissions:${String(e)}`}async function ote(){const e=tte(),t=nte(e);try{const o=JSON.parse(window.localStorage.getItem(t)||"null");if(Array.isArray(o))return o.map(a=>String(a.column_key||"").trim().toLowerCase()).filter(Boolean)}catch{}const n=await ete(`/api/admin/user/${encodeURIComponent(String(e))}/column-permissions`,{params:{menu_type:"app"}});if(!n.success)throw new Error(n.error||"获取菜单权限失败");try{window.localStorage.setItem(t,JSON.stringify(n.items||[]))}catch{}return(n.items||[]).map(o=>String(o.column_key||"").trim().toLowerCase()).filter(Boolean)}let Xh,Ow=!1;function qx(){return Xh=window.pywebview?.api,Xh}function ate(){Ow||typeof window>"u"||!window.addEventListener||(Ow=!0,window.addEventListener("pywebviewready",()=>{qx()}))}ate();function ste(){return qx()||Xh}const Yi=Mt({});let Rw=!1;function rte(e){return Number.isFinite(e)?Math.max(0,Math.min(100,Math.round(e))):0}function lte(){return Date.now()}function Yr(e){const t=Yi[e.id],n=lte();Yi[e.id]={id:e.id,filename:e.filename||t?.filename||"下载文件",status:e.status||t?.status||"running",path:e.path??t?.path,downloaded:Number(e.downloaded??t?.downloaded??0),total:Number(e.total??t?.total??0),percent:rte(Number(e.percent??t?.percent??0)),error:e.error??t?.error,createdAt:t?.createdAt||n,updatedAt:n}}function ite(e){const t=e.detail;t?.id&&Yr({id:t.id,status:t.status,path:t.path,downloaded:t.downloaded,total:t.total,percent:t.percent,error:t.error})}function Yx(){Rw||typeof window>"u"||(Rw=!0,window.addEventListener("pywebview-download-progress",ite))}function ute(){return Yx(),{items:w(()=>Object.values(Yi).filter(t=>t.status!=="cancelled").sort((t,n)=>n.createdAt-t.createdAt)),clearDownloadProgress:gg}}function gg(e){delete Yi[e]}function cte(e){const t=e.replace(/[^a-zA-Z0-9._-]+/g,"-").slice(0,60)||"download";return`download:${Date.now()}:${Math.random().toString(16).slice(2)}:${t}`}async function one(e,t,n=cte(t)){Yx();const o=ste();if(!o?.save_file_from_url_new)return Yr({id:n,filename:t,status:"failed",downloaded:0,total:0,percent:0,error:"当前客户端未提供下载能力"}),{success:!1,error:"当前客户端未提供下载能力"};Yr({id:n,filename:t,status:"selecting",downloaded:0,total:0,percent:0});const a=o.save_file_from_url_with_progress?await o.save_file_from_url_with_progress(e,t,n):await o.save_file_from_url_new(e,t);if(a.success){const s=Yi[n];Yr({id:n,filename:t,status:"success",path:a.path,downloaded:s?.downloaded||s?.total||0,total:s?.total||s?.downloaded||0,percent:100})}else a.error==="用户取消"?(Yr({id:n,filename:t,status:"cancelled",downloaded:0,total:0,percent:0}),gg(n)):Yr({id:n,filename:t,status:"failed",downloaded:0,total:0,percent:0,error:a.error||"下载失败"});return a}function Nw(e){const t=Number(e||0);return!Number.isFinite(t)||t<=0?"未知大小":t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:t<1024*1024*1024?`${(t/1024/1024).toFixed(1)} MB`:`${(t/1024/1024/1024).toFixed(2)} GB`}function dte(e){return e.status==="selecting"?"等待选择保存位置":e.status==="success"?"下载完成":e.status==="failed"?e.error||"下载失败":e.total>0?"正在下载,请等待完成后再打开":"正在下载,正在获取文件大小"}const fte={key:0,class:"download-progress-panel"},pte={class:"download-progress-head"},hte=["title"],vte=["onClick"],mte={class:"download-progress-meta"},gte={class:"download-progress-track"},bte={class:"download-progress-size"},yte=se({__name:"DownloadProgressPanel",setup(e){const{items:t}=ute(),n=w(()=>t.value.slice(0,5));return(o,a)=>n.value.length?(x(),B("div",fte,[a[0]||(a[0]=V("div",{class:"download-progress-title"},"下载进度",-1)),(x(!0),B(Fe,null,gt(n.value,s=>(x(),B("div",{key:s.id,class:T(["download-progress-item",s.status])},[V("div",pte,[V("span",{class:"download-progress-name",title:s.filename},we(s.filename),9,hte),V("button",{type:"button",class:"download-progress-close",onClick:r=>i(gg)(s.id)},"×",8,vte)]),V("div",mte,[V("span",null,we(i(dte)(s)),1),V("span",null,we(s.percent)+"%",1)]),V("div",gte,[V("div",{class:"download-progress-bar",style:Ke({width:`${s.percent}%`})},null,4)]),V("div",bte,we(i(Nw)(s.downloaded))+" / "+we(i(Nw)(s.total)),1)],2))),128))])):te("",!0)}}),wte=dg(yte,[["__scopeId","data-v-5a9fa6a2"]]),Ste={class:"top-bar"},Cte={class:"nav-sections","aria-label":"顶部功能导航"},kte={class:"nav-section-title"},Ete={class:"nav-section-items"},xte=["href"],Tte={class:"top-right"},$te=se({__name:"BrandTopBar",props:{active:{}},setup(e){const n=e.active,o=P(null),a=[{columnKey:"brand_front_tools",label:"前端工具",items:[{key:"collect-data",label:"采集数据",href:"/new_web_source/collect-data.html"},{key:"variant",label:"变体分析"},{key:"brand",label:"品牌检测",href:"/brand"},{key:"appearance-patent",label:"外观专利检测",href:"/new_web_source/appearance-patent.html"},{key:"similar-asin",label:"货源查询",href:"/new_web_source/similar-asin.html"},{key:"dedupe",label:"数据去重",href:"/new_web_source/dedupe.html"},{key:"split",label:"数据拆分",href:"/new_web_source/split.html"},{key:"convert",label:"格式转换",href:"/new_web_source/convert.html"}]},{columnKey:"brand_operation_tools",label:"运营工具",items:[{key:"delete-brand",label:"删除ASIN",href:"/new_web_source/delete-brand.html"},{key:"product-risk",label:"商品风险解决",href:"/new_web_source/product-risk.html"},{key:"shop-match",label:"定时匹配",href:"/new_web_source/shop-match.html"},{key:"pricing",label:"跟价",href:"/new_web_source/price-track.html"},{key:"patrol-delete",label:"巡店删除",href:"/new_web_source/patrol-delete.html"},{key:"query-asin",label:"查询ASIN",href:"/new_web_source/query-asin.html"},{key:"withdraw",label:"取款"},{key:"shop-status",label:"店铺状态查询"}]},{columnKey:"brand_logistics_tools",label:"后勤工具",items:[{key:"purchase",label:"采购"},{key:"erp",label:"ERP"}]}],s=w(()=>{if(o.value===null)return a;const r=new Set(o.value);return a.filter(l=>r.has(l.columnKey))});return ht(async()=>{try{o.value=await ote()}catch{o.value=null}}),(r,l)=>(x(),B("header",Ste,[l[0]||(l[0]=V("div",{class:"logo-area"},[V("span",{class:"app-name"},"数富AI-亚马逊"),V("a",{href:"/home",class:"btn-home"},"返回首页")],-1)),V("nav",Cte,[(x(!0),B(Fe,null,gt(s.value,u=>(x(),B("section",{key:u.columnKey,class:"nav-section"},[V("div",kte,we(u.label),1),V("div",Ete,[(x(!0),B(Fe,null,gt(u.items,c=>(x(),B(Fe,{key:c.key},[c.href?(x(),B("a",{key:0,href:c.href,class:T(["nav-item",{active:i(n)===c.key}])},we(c.label),11,xte)):(x(),B("span",{key:1,class:T(["nav-item disabled",{active:i(n)===c.key}])},we(c.label),3))],64))),128))])]))),128))]),V("div",Tte,[Y(gQ)]),Y(wte)]))}}),ane=dg($te,[["__scopeId","data-v-74abee09"]]),Ote=1e4,Rte=6e4,Nte=5e3,Ite=3e4;function sne(){return typeof document<"u"&&document.visibilityState!=="visible"?Rte:Ote}function _te(){return typeof document<"u"&&document.hidden?Ite:Nte}const je="/newApi/api",Iw=new Map,Ep=new Map;function Ze(){const e=typeof window>"u"?"":window.localStorage.getItem("uid")||"",t=Number(e);if(!Number.isFinite(t)||t<=0)throw new Error("未获取到用户ID");return t}function Pte(e){return Array.from(new Set((e||[]).map(t=>Number(t)).filter(t=>Number.isFinite(t)&&t>0))).sort((t,n)=>t-n)}function Mte(e,t){return`${e}::${t.join(",")}`}async function ys(e,t,n={}){const o=Pte(t);if(!o.length)return{items:[],missingTaskIds:[]};const a=Mte(e,o),s=Date.now(),r=Iw.get(a);if(!n.force&&r&&r.expiresAt>s)return r.data;const l=Ep.get(a);if(!n.force&&l)return await l;const u=Ge(Qt(e,{taskIds:o})).then(c=>(Iw.set(a,{data:c,expiresAt:Date.now()+_te()}),c)).finally(()=>{Ep.delete(a)});return Ep.set(a,u),u}function rne(e){return Ge(Zt(`${je}/files/excel-info`,{params:{fileKey:e}}))}function lne(e){return Ge(Qt(`${je}/dedupe/run`,{...e,user_id:Ze()}))}function ine(){return Ge(Zt(`${je}/dedupe/history`,{params:{user_id:Ze()}}))}function une(e){return Ge(cn(`${je}/dedupe/history/${e}`,{params:{user_id:Ze()}}))}function cne(e){return Wo(`/dedupe/results/${e}/download`)}function dne(e){return Ge(Qt(`${je}/split/run`,{...e,user_id:Ze()}))}function fne(){return Ge(Zt(`${je}/split/history`,{params:{user_id:Ze()}}))}function pne(e){return Ge(cn(`${je}/split/history/${e}`,{params:{user_id:Ze()}}))}function hne(e){return Wo(`/split/results/${e}/download`)}function vne(){return Ge(Zt(`${je}/convert/templates`))}function mne(e){return Ge(Qt(`${je}/convert/run`,{...e,user_id:Ze()}))}function gne(){return Ge(Zt(`${je}/convert/history`,{params:{user_id:Ze()}}))}function bne(e){return Ge(cn(`${je}/convert/history/${e}`,{params:{user_id:Ze()}}))}function yne(e){return Wo(`/convert/results/${e}/download`)}function wne(e){return Ge(Qt(`${je}/delete-brand/run`,{...e,user_id:Ze()},{timeout:18e4}))}function Sne(){return Ge(Zt(`${je}/delete-brand/history`,{params:{user_id:Ze()}}))}function Cne(e){return Ge(cn(`${je}/delete-brand/history/${e}`,{params:{user_id:Ze()}}))}function kne(e){return Wo(`/delete-brand/tasks/${e}/download`)}function Ene(e){return Wo(`/delete-brand/results/${e}/download`)}function xne(){return Ge(Zt(`${je}/product-risk-resolve/candidates`,{params:{user_id:Ze()}}))}function Tne(e){return Ge(Qt(`${je}/product-risk-resolve/candidates`,{user_id:Ze(),shop_name:e}))}function $ne(e){return Ge(cn(`${je}/product-risk-resolve/candidates/${e}`,{params:{user_id:Ze()}}))}function One(){return Ge(Zt(`${je}/product-risk-resolve/country-preference`,{params:{user_id:Ze()}}))}function Rne(e){return Ge(Ef(`${je}/product-risk-resolve/country-preference`,{user_id:Ze(),country_codes:e}))}function Nne(e){return Ge(Qt(`${je}/product-risk-resolve/match-shops`,{user_id:Ze(),shop_names:e}))}function Ine(){return Ge(Zt(`${je}/product-risk-resolve/dashboard`,{params:{user_id:Ze()}}))}function _ne(){return Ge(Zt(`${je}/product-risk-resolve/history`,{params:{user_id:Ze()}}))}function Pne(e){return Ge(cn(`${je}/product-risk-resolve/history/${e}`,{params:{user_id:Ze()}}))}function Mne(e){return Ge(Qt(`${je}/product-risk-resolve/tasks`,{user_id:Ze(),items:e}))}function Ane(e){return Ge(cn(`${je}/product-risk-resolve/tasks/${e}`,{params:{user_id:Ze()}}))}function Lne(e){return Ge(cn(`${je}/product-risk-resolve/pending-shop-result`,{params:{user_id:Ze(),shop_name:e}}))}function Dne(e){return Wo(`/product-risk-resolve/results/${e}/download`)}function Bne(){return Ge(Zt(`${je}/shop-match/candidates`,{params:{user_id:Ze()}}))}function Fne(e){return Ge(Qt(`${je}/shop-match/candidates`,{user_id:Ze(),shop_name:e}))}function Vne(e){return Ge(cn(`${je}/shop-match/candidates/${e}`,{params:{user_id:Ze()}}))}function zne(){return Ge(Zt(`${je}/shop-match/country-preference`,{params:{user_id:Ze()}}))}function Hne(e){return Ge(Ef(`${je}/shop-match/country-preference`,{user_id:Ze(),country_codes:e}))}function Kne(e){return Ge(Qt(`${je}/shop-match/match-shops`,{user_id:Ze(),shop_names:e}))}function Wne(){return Ge(Zt(`${je}/shop-match/dashboard`,{params:{user_id:Ze()}}))}function jne(){return Ge(Zt(`${je}/shop-match/history`,{params:{user_id:Ze()}}))}function Une(e){return Ge(cn(`${je}/shop-match/history/${e}`,{params:{user_id:Ze()}}))}function qne(e,t,n){return Ge(Qt(`${je}/shop-match/tasks`,{user_id:Ze(),items:e,country_codes:t,schedule_times:n}))}function Yne(e){return Ge(cn(`${je}/shop-match/tasks/${e}`,{params:{user_id:Ze()}}))}function Gne(e,t){return Ge(Qt(`${je}/shop-match/tasks/${e}/activate?user_id=${encodeURIComponent(String(Ze()))}&stage_index=${encodeURIComponent(String(t))}`,void 0))}function Xne(e){return Wo(`/shop-match/results/${e}/download`)}function Jne(){return Ge(Zt(`${je}/patrol-delete/candidates`,{params:{user_id:Ze()}}))}function Zne(e){return Ge(Qt(`${je}/patrol-delete/candidates`,{user_id:Ze(),shop_name:e}))}function Qne(e){return Ge(cn(`${je}/patrol-delete/candidates/${e}`,{params:{user_id:Ze()}}))}function eoe(){return Ge(Zt(`${je}/patrol-delete/conditions`,{params:{user_id:Ze()}}))}function toe(e){return Ge(Qt(`${je}/patrol-delete/conditions`,{user_id:Ze(),condition_text:e}))}function noe(e){return Ge(cn(`${je}/patrol-delete/conditions/${e}`,{params:{user_id:Ze()}}))}function ooe(e){return Ge(Qt(`${je}/patrol-delete/match-shops`,{user_id:Ze(),shop_names:e}))}function aoe(){return Ge(Zt(`${je}/patrol-delete/dashboard`,{params:{user_id:Ze()}}))}function soe(){return Ge(Zt(`${je}/patrol-delete/history`,{params:{user_id:Ze()}}))}function roe(e){return ys(`${je}/patrol-delete/tasks/progress/batch`,e)}function loe(e){return Ge(Qt(`${je}/patrol-delete/tasks`,{user_id:Ze(),items:e}))}function ioe(e,t){return Ge(Qt(`${je}/patrol-delete/tasks/${e}/result`,t))}function uoe(e){return Wo(`/patrol-delete/results/${e}/download`)}function coe(e){return Ge(cn(`${je}/patrol-delete/tasks/${e}`,{params:{user_id:Ze()}}))}function doe(e){return Ge(cn(`${je}/patrol-delete/history/${e}`,{params:{user_id:Ze()}}))}function foe(){return Ge(Zt(`${je}/query-asin/candidates`,{params:{user_id:Ze()}}))}function poe(e){return Ge(Qt(`${je}/query-asin/candidates`,{user_id:Ze(),shop_name:e}))}function hoe(e){return Ge(cn(`${je}/query-asin/candidates/${e}`,{params:{user_id:Ze()}}))}function voe(e){return Ge(Qt(`${je}/query-asin/match-shops`,{user_id:Ze(),shop_names:e}))}function moe(){return Ge(Zt(`${je}/query-asin/dashboard`,{params:{user_id:Ze()}}))}function goe(){return Ge(Zt(`${je}/query-asin/history`,{params:{user_id:Ze()}}))}function boe(e){return ys(`${je}/query-asin/tasks/progress/batch`,e)}function yoe(e){return Ge(Qt(`${je}/query-asin/tasks`,{user_id:Ze(),items:e}))}function woe(e,t){return Ge(Qt(`${je}/query-asin/tasks/${e}/result`,t))}function Soe(e){return Wo(`/query-asin/results/${e}/download`)}function Coe(e){return Ge(cn(`${je}/query-asin/tasks/${e}`,{params:{user_id:Ze()}}))}function koe(e){return Ge(cn(`${je}/query-asin/history/${e}`,{params:{user_id:Ze()}}))}function Eoe(e,t,n){return Ge(Qt(`${je}/appearance-patent/parse`,{user_id:Ze(),files:e,ai_prompt:t,api_key:n}))}function xoe(e){return Ge(Zt(`${je}/appearance-patent/tasks/${e}/queue-payload`,{params:{user_id:Ze()}}))}function Toe(){return Ge(Zt(`${je}/appearance-patent/dashboard`,{params:{user_id:Ze()}}))}function $oe(){return Ge(Zt(`${je}/appearance-patent/history`,{params:{user_id:Ze(),limit:50}}))}function Ooe(e,t={}){return ys(`${je}/appearance-patent/tasks/progress/batch`,e,t)}function Roe(e){return Ge(Qt(`${je}/appearance-patent/tasks/${e}/activate?user_id=${encodeURIComponent(String(Ze()))}`,void 0))}function Noe(e){return Ge(cn(`${je}/appearance-patent/tasks/${e}`,{params:{user_id:Ze()}}))}function Ioe(e){return Ge(cn(`${je}/appearance-patent/history/${e}`,{params:{user_id:Ze()}}))}function _oe(e){return Wo(`/appearance-patent/results/${e}/download`)}function Poe(e,t,n=!1){return Ge(Qt(`${je}/similar-asin/parse`,{user_id:Ze(),files:e,api_key:t,img_switch:n}))}function Moe(){return Ge(Zt(`${je}/similar-asin/dashboard`,{params:{user_id:Ze()}}))}function Aoe(){return Ge(Zt(`${je}/similar-asin/history`,{params:{user_id:Ze(),limit:50}}))}function Loe(e,t={}){return ys(`${je}/similar-asin/tasks/progress/batch`,e,t)}function Doe(e){return Ge(Qt(`${je}/similar-asin/tasks/${e}/activate?user_id=${encodeURIComponent(String(Ze()))}`,void 0))}function Boe(e){return Ge(cn(`${je}/similar-asin/tasks/${e}`,{params:{user_id:Ze()}}))}function Foe(e){return Ge(cn(`${je}/similar-asin/history/${e}`,{params:{user_id:Ze()}}))}function Voe(e){return Wo(`/similar-asin/results/${e}/download`)}function zoe(){return Ge(Zt(`${je}/price-track/candidates?user_id=${encodeURIComponent(String(Ze()))}`))}function Hoe(e){return Ge(Qt(`${je}/price-track/candidates`,{userId:Ze(),shopName:e}))}function Koe(e){return Ge(cn(`${je}/price-track/candidates/${e}?user_id=${encodeURIComponent(String(Ze()))}`))}function Woe(){return Ge(Zt(`${je}/price-track/country-preference?user_id=${encodeURIComponent(String(Ze()))}`))}function joe(e){return Ge(Ef(`${je}/price-track/country-preference`,{userId:Ze(),countryCodes:e}))}function Uoe(e,t){return Ge(Qt(`${je}/price-track/match-shops`,{userId:Ze(),shopNames:e,asinFiles:t?.asinFiles||[],countryCodes:t?.countryCodes||[]}))}function qoe(e){return ys(`${je}/shop-match/tasks/progress/batch`,e)}function Yoe(e){return ys(`${je}/product-risk-resolve/tasks/progress/batch`,e)}function Goe(e){return ys(`${je}/delete-brand/tasks/progress/batch`,e)}function Xoe(){return Ge(Zt(`${je}/price-track/dashboard?user_id=${encodeURIComponent(String(Ze()))}`))}function Joe(){return Ge(Zt(`${je}/price-track/history?user_id=${encodeURIComponent(String(Ze()))}`))}function Zoe(e){return Ge(cn(`${je}/price-track/history/${e}?user_id=${encodeURIComponent(String(Ze()))}`))}function Qoe(e){return Ge(Qt(`${je}/price-track/tasks`,{...e,userId:Ze()}))}function eae(e){return Ge(cn(`${je}/price-track/tasks/${e}?user_id=${encodeURIComponent(String(Ze()))}`))}function tae(e){return Ge(Qt(`${je}/price-track/loop-runs`,{...e,userId:Ze()}))}function nae(e){return Ge(Zt(`${je}/price-track/loop-runs/${e}?user_id=${encodeURIComponent(String(Ze()))}`))}function oae(e){return Ge(Qt(`${je}/price-track/loop-runs/${e}/dispatch-next?user_id=${encodeURIComponent(String(Ze()))}`,void 0))}function aae(e,t){return Ge(Qt(`${je}/price-track/loop-runs/${e}/child-finished?user_id=${encodeURIComponent(String(Ze()))}`,{childTaskId:t}))}function sae(e){return Ge(Qt(`${je}/price-track/loop-runs/${e}/stop?user_id=${encodeURIComponent(String(Ze()))}`,void 0))}function rae(e){return ys(`${je}/price-track/tasks/progress/batch`,e)}function lae(e){return Wo(`/price-track/results/${e}/download`)}function iae(e){return Ge(cn(`${je}/price-track/pending-shop-result?user_id=${encodeURIComponent(String(Ze()))}&shop_name=${encodeURIComponent(e)}`))}function uae(e){return Ge(Qt(`${je}/collect-data/parse`,{...e,user_id:Ze()}))}function cae(e){return Ge(Qt(`${je}/collect-data/tasks/${e}/activate?user_id=${encodeURIComponent(String(Ze()))}`,void 0))}function dae(){return Ge(Zt(`${je}/collect-data/dashboard`,{params:{user_id:Ze()}}))}function fae(e=50){return Ge(Zt(`${je}/collect-data/history`,{params:{user_id:Ze(),limit:e}}))}function pae(e,t={}){return ys(`${je}/collect-data/tasks/progress/batch`,e,t)}function hae(e){return Ge(cn(`${je}/collect-data/tasks/${e}`,{params:{user_id:Ze()}}))}function vae(e){return Ge(cn(`${je}/collect-data/history/${e}`,{params:{user_id:Ze()}}))}function mae(){return Ge(Zt(`${je}/collect-data/country-preference`,{params:{user_id:Ze()}}))}function gae(e){return Ge(Ef(`${je}/collect-data/country-preference`,{user_id:Ze(),country_codes:e}))}function Wo(e){let t=e.startsWith("http://")||e.startsWith("https://")?e:`${je}${e}`;!t.startsWith("http://")&&!t.startsWith("https://")&&typeof window<"u"&&(t=`${window.location.origin}${t}`);const n=t.includes("?")?"&":"?";return`${t}${n}user_id=${encodeURIComponent(String(Ze()))}`}export{$oe as $,mne as A,ane as B,gne as C,bne as D,Wh as E,Fe as F,yne as G,wv as H,dne as I,fne as J,pne as K,hne as L,Ol as M,Ate as N,Ke as O,Goe as P,wne as Q,Ene as R,kne as S,Sne as T,Cne as U,sne as V,Eoe as W,xoe as X,Roe as Y,Toe as Z,dg as _,x as a,Qoe as a$,_oe as a0,Noe as a1,Ioe as a2,Dte as a3,Ooe as a4,Poe as a5,Doe as a6,Moe as a7,Aoe as a8,Voe as a9,Mne as aA,S5 as aB,Bne as aC,Wne as aD,jne as aE,zne as aF,Fne as aG,Vne as aH,Kne as aI,Xne as aJ,Yne as aK,Une as aL,qne as aM,Hne as aN,qoe as aO,Gne as aP,st as aQ,q2 as aR,joe as aS,Woe as aT,zoe as aU,Xoe as aV,Joe as aW,Hoe as aX,Koe as aY,Uoe as aZ,iae as a_,Boe as aa,Foe as ab,Loe as ac,an as ad,eo as ae,J as af,Tq as ag,xq as ah,Je as ai,i as aj,ae as ak,ud as al,Ks as am,Rne as an,One as ao,Lne as ap,Pne as aq,Ane as ar,Ine as as,xne as at,_ne as au,Yoe as av,Tne as aw,$ne as ax,Nne as ay,Dne as az,Y as b,nae as b0,sae as b1,aae as b2,oae as b3,tae as b4,lae as b5,Zoe as b6,eae as b7,rae as b8,Jne as b9,y8 as bA,le as bB,Bt as bC,Mt as bD,gae as bE,mae as bF,uae as bG,cae as bH,dae as bI,fae as bJ,vae as bK,hae as bL,pae as bM,nne as bN,eoe as ba,aoe as bb,soe as bc,Zne as bd,toe as be,noe as bf,Qne as bg,ooe as bh,loe as bi,ioe as bj,uoe as bk,coe as bl,doe as bm,roe as bn,foe as bo,moe as bp,goe as bq,poe as br,hoe as bs,voe as bt,yoe as bu,woe as bv,Soe as bw,Coe as bx,koe as by,boe as bz,B as c,se as d,V as e,te as f,P as g,w as h,ste as i,lne as j,ine as k,une as l,cne as m,T as n,ht as o,rne as p,mO as q,gt as r,one as s,we as t,Lte as u,tS as v,ut as w,Sv as x,wt as y,vne as z}; diff --git a/app/assets/patrol-delete.js b/app/assets/patrol-delete.js index 69eb3b2..b4de7e7 100644 --- a/app/assets/patrol-delete.js +++ b/app/assets/patrol-delete.js @@ -1 +1 @@ -import{d as ie,o as ue,M as ce,a as i,c as u,b as m,B as de,e as a,ad as Mt,ae as fe,t as r,af as S,ag as pe,ah as he,F as W,r as ut,w as me,v as ve,f as v,ak as ye,n as ct,y as At,g as p,h as M,b9 as _e,ba as we,bb as ge,bc as ke,E as d,bd as be,be as Se,bf as Ie,bg as Te,bh as Ce,i as Ee,bi as De,bj as Pe,bk as Ne,s as $e,bl as Re,bm as Me,V as X,bn as Ae,_ as Le,aQ as qe,q as Be,u as xe}from"./java-modules-DzYrjxib.js";import{z as Ue}from"./zh-cn-z8KAT-CE.js";/* empty css */import{c as Fe}from"./categorized-timers-JPA-olTr.js";const He={class:"page-shell module-page"},Oe={class:"main-content"},Ve={class:"left-panel"},Qe={class:"input-zone"},Ke={class:"input-row"},ze=["disabled"],Ge={key:0,class:"empty-candidates"},je={key:1,class:"candidate-table-scroll"},Je=["onClick"],We={class:"condition-panel"},Xe={class:"condition-input-row"},Ye=["disabled"],Ze={key:0,class:"empty-conditions"},ts={key:1,class:"condition-list"},es={class:"condition-check"},ss=["value"],as=["title"],ns=["onClick"],os={class:"run-row"},ls=["disabled"],rs=["disabled"],is={key:2,class:"queue-debug-card"},us={class:"queue-debug-line"},cs={key:0,class:"queue-debug-payload"},ds={class:"right-panel"},fs={class:"task-list-wrap"},ps={class:"clean-result-summary"},hs={class:"summary-card"},ms={class:"summary-card"},vs={class:"summary-card"},ys={class:"summary-card"},_s={key:0,class:"empty-tasks narrow"},ws=["onClick"],gs={class:"result-list-wrap"},ks={key:0,class:"empty-tasks"},bs={key:0,class:"result-subsection"},Ss={class:"task-list"},Is={class:"left split-result-main"},Ts=["title"],Cs={class:"files"},Es={key:0,class:"files"},Ds={key:1,class:"files"},Ps={key:2,class:"files"},Ns={class:"files"},$s={class:"files"},Rs={key:3,class:"files"},Ms={class:"task-right"},As=["onClick"],Ls={key:1,class:"result-subsection"},qs={class:"task-list"},Bs={class:"left split-result-main"},xs=["title"],Us={class:"files"},Fs={key:0,class:"files"},Hs={key:1,class:"files"},Os={key:2,class:"files"},Vs={class:"files"},Qs={key:3,class:"files"},Ks={class:"files"},zs={key:4,class:"files"},Gs={class:"task-right"},js=["onClick"],Js=["onClick"],Lt=30,Ws=ie({__name:"BrandPatrolDeleteTab",setup(Ys){const dt=["德国","英国","法国","意大利","西班牙"],A=p(""),L=p(""),Y=p([]),q=p([]),D=p([]),_=p([]),w=p([]),k=p([]),P=p({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),B=p(!1),x=p(!1),U=p(!1),F=p(!1),y=p(""),Z=p(""),h=p(null),H=p(!1);let I=null;const T=Fe("patrol-delete"),tt=M(()=>w.value.filter(t=>t.matched)),ft=M(()=>Vt(k.value)),O=M(()=>ft.value.filter(t=>!gt(t.taskStatus))),et=M(()=>ft.value.filter(t=>gt(t.taskStatus))),V=M(()=>H.value||!!h.value);function st(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function pt(){return`patrol-delete:matched:${st()}`}function ht(){return`patrol-delete:queue-state:${st()}`}function N(t){return`${(t.shopName||"").trim()}::${t.shopId||""}`}function Q(t){return`${t.taskId??0}:${t.resultId??0}`}function mt(t){return`task:${t.taskId??t.resultId??0}`}let g=!1;function vt(t){return g?Promise.resolve():T.sleep("queue-wait",t)}function qt(){T.clearCategory("queue-wait")}function yt(t){const e=t instanceof Error?t.message.toLowerCase():String(t||"").toLowerCase();return e.includes("network error")||e.includes("failed to fetch")||e.includes("timeout")||e.includes("503")||e.includes("502")||e.includes("504")||e.includes("500")||e.includes("load failed")}async function Bt(t,e,o=20){let n=0;for(;;){if(g)throw new Error("component disposed");try{return await t()}catch(l){if(!yt(l)||n>=o-1)throw l;n+=1,e?.(n,o),await vt(X())}}}function xt(t,e){return`patrol-delete:${t}:${e||"shop"}:${Date.now()}`}function at(t){if(!t)return"-";const e=new Date(t);if(Number.isNaN(e.getTime()))return t;const o=e.getFullYear(),n=String(e.getMonth()+1).padStart(2,"0"),l=String(e.getDate()).padStart(2,"0"),s=String(e.getHours()).padStart(2,"0"),f=String(e.getMinutes()).padStart(2,"0"),c=String(e.getSeconds()).padStart(2,"0");return`${o}-${n}-${l} ${s}:${f}:${c}`}function Ut(t){const e=(t||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[e]||e||"-"}function Ft(t){const e=(t.matchMessage||"").trim();return e||(t.matched&&t.matchStatus==="MATCHED"?"索引已命中,可推送到 Python 队列":t.matched?"已命中索引,请结合状态列确认":"未命中或未就绪,请检查店铺名")}function Ht(){return dt.map(t=>({country:t,rows:[{status:"全部",quantity:"",deleteQuantity:"",processStatus:""}]}))}function Ot(){return dt.map(t=>({country:t,ratio:""}))}function _t(t){const e=t.countrySections||[],o=t.cartRatios||[],n=Math.max(...e.map(l=>l.rows.length),1);return Array.from({length:n},(l,s)=>({shopName:s===0?t.shopName:"",countries:e.map(f=>{const c=f.rows[s];return{country:f.country,status:c?.status||"",quantity:c?.quantity||"",deleteQuantity:c?.deleteQuantity||"",processStatus:c?.processStatus||""}}),cartRatios:s===0?o.map(f=>({country:f.country,ratio:f.ratio})):[]}))}function wt(t){return`${new Set([...(t.countrySections||[]).map(o=>o.country).filter(Boolean),...(t.cartRatios||[]).map(o=>o.country).filter(Boolean)]).size||0} 个国家,含状态数据和购物车比例`}function b(t){return Array.from(new Set(t.map(e=>e==null?"":String(e).trim()).filter(Boolean))).join("、")}function Vt(t){const e=new Map;for(const o of t||[]){const n=String(o.taskId??`result:${o.resultId??Math.random()}`),l=e.get(n)||[];l.push(o),e.set(n,l)}return Array.from(e.values()).map(o=>{const n=o.find(s=>St(s))||o.find(s=>s.taskStatus)||o[0],l=b(o.map(s=>s.error));return{...n,shopName:b(o.map(s=>s.shopName))||n.shopName,shopId:b(o.map(s=>s.shopId))||n.shopId,error:l||n.error,__groupItems:o}})}function C(t){return t.__groupItems||[t]}function K(t){return b(C(t).map(e=>e.shopName))||"-"}function z(t){return b(C(t).map(e=>e.resultId))}function G(t){return b(C(t).map(e=>e.shopId))}function j(t){return b(C(t).map(e=>e.error))}function gt(t){return t==="SUCCESS"||t==="FAILED"||t==="COMPLETED"}function kt(t){return t==="SUCCESS"||t==="COMPLETED"?"已完成":t==="FAILED"?"失败":"执行中"}function bt(t){return t==="SUCCESS"||t==="COMPLETED"?"success":t==="FAILED"?"failed":"running"}function St(t){return C(t).some(e=>!!(e.resultId&&(e.fileReady||e.downloadUrl)))}function It(){typeof window>"u"||window.localStorage.setItem(pt(),JSON.stringify(w.value))}function Qt(){try{const t=typeof window<"u"?window.localStorage.getItem(pt()):null;w.value=t?JSON.parse(t):[]}catch{w.value=[]}}function nt(){if(typeof window>"u")return;const t={activeTaskId:h.value};window.localStorage.setItem(ht(),JSON.stringify(t))}function Kt(){try{const t=typeof window<"u"?window.localStorage.getItem(ht()):null;if(!t)return;const e=JSON.parse(t);h.value=e.activeTaskId??null}catch{h.value=null}}function E(){h.value=null,nt()}function zt(t){const e=t instanceof Error?t.message:String(t||"");return/记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(e)}function ot(t){const e=N(t);w.value=w.value.filter(o=>N(o)!==e),It()}function Tt(t){k.value=k.value.filter(e=>!(t.resultId!=null&&e.resultId===t.resultId||t.taskId!=null&&e.taskId===t.taskId))}async function $(){Y.value=await _e()}async function lt(){D.value=await we();const t=new Set(D.value.map(e=>e.id));_.value=_.value.filter(e=>t.has(e))}async function R(){P.value=await ge()}async function rt(){const t=await ke();k.value=t.items||[]}async function J(){await Promise.all([R(),rt()])}function Ct(t){if(!t.length)return;const e=new Map(t.map(n=>[Q(n),n])),o=k.value.map(n=>{const l=e.get(Q(n));return l?{...n,...l,countrySections:l.countrySections||n.countrySections||[],cartRatios:l.cartRatios||n.cartRatios||[]}:n});for(const n of t){const l=Q(n);o.some(s=>Q(s)===l)||o.push(n)}k.value=o}function Gt(t){Ct(t)}async function Et(t){const e=Array.from(new Set((t&&t.length?t:O.value.map(n=>n.taskId??0)).filter(n=>Number.isFinite(n)&&n>0)));if(!e.length)return[];const o=await Ae(e);return Ct(o.items||[]),(o.missingTaskIds||[]).length&&await rt(),o.missingTaskIds||[]}function jt(){if(it(),g||!V.value)return;const t=async()=>{I=null,!(g||!V.value)&&(await Et(),!g&&V.value&&(I=T.setTimeout("history-poll",t,X()*2)))};I=T.setTimeout("history-poll",t,X()*2)}function it(){I&&(T.clearTimer("history-poll",I),I=null)}function Jt(t){q.value=t}async function Dt(){const t=A.value.trim();if(!t){d.warning("请输入店铺名");return}B.value=!0;try{await be(t),A.value="",await Promise.all([$(),R()]),d.success("已加入备选区")}catch(e){d.error(e instanceof Error?e.message:"添加失败")}finally{B.value=!1}}async function Pt(){const t=L.value.trim();if(!t){d.warning("请输入删除条件");return}x.value=!0;try{const e=await Se(t);L.value="",await lt(),e?.id&&!_.value.includes(e.id)&&(_.value=[..._.value,e.id]),d.success("删除条件已保存")}catch(e){d.error(e instanceof Error?e.message:"保存失败")}finally{x.value=!1}}async function Wt(t){try{await Ie(t),_.value=_.value.filter(e=>e!==t),await lt(),d.success("删除条件已删除")}catch(e){d.error(e instanceof Error?e.message:"删除失败")}}async function Xt(t){try{await Te(t),q.value=q.value.filter(e=>e.id!==t),await Promise.all([$(),R()]),d.success("已删除")}catch(e){d.error(e instanceof Error?e.message:"删除失败")}}function Yt(t,e){const o=new Map;for(const n of t)o.set(N(n),n);for(const n of e)o.set(N(n),n);return Array.from(o.values())}async function Zt(){const t=q.value.map(e=>e.shop_name).filter(Boolean);if(!t.length){d.warning("请先勾选备选区店铺");return}U.value=!0;try{const e=await Ce(t);w.value=Yt(w.value,e.items||[]),It(),d.success(`本次返回 ${e.items?.length||0} 条匹配结果`)}catch(e){d.error(e instanceof Error?e.message:"匹配失败")}finally{U.value=!1}}function te(t){ot(t),d.success("已从匹配结果移除")}function ee(t){return{shopName:t.shopName,matched:t.matched,shopId:t.shopId,platform:t.platform,companyName:t.companyName,matchStatus:t.matchStatus,matchMessage:t.matchMessage,countrySections:Ht(),cartRatios:Ot()}}function se(){const t=new Set(_.value);return D.value.filter(e=>t.has(e.id)).map(e=>({id:e.id,conditionText:e.conditionText}))}function ae(t,e){const o=e[0],n=se();return{type:"patrol-delete-run",ts:Date.now(),data:{taskId:t,user_id:Number(st())||0,source:"frontend-vue-patrol-delete",delete_conditions:n,deleteConditions:n,items:e.map(l=>({shopName:l.shopName,shopId:l.shopId,platform:l.platform,companyName:l.companyName,matched:l.matched,matchStatus:l.matchStatus,matchMessage:l.matchMessage,countrySections:l.countrySections||[],cartRatios:l.cartRatios||[]})),template_rows:o?_t(o):[],shop_template_rows:e.map(l=>({shopName:l.shopName,shopId:l.shopId,templateRows:_t(l)})),country_sections:o?.countrySections||[],cart_ratios:o?.cartRatios||[]}}}function ne(t){return k.value.find(e=>e.taskId===t)}async function Nt(t){let e=0;for(;;){if(g)return"STOPPED";if(h.value!==t)return"DELETED";try{if((await Et([t])).includes(t))return E(),"DELETED";if(h.value!==t)return"DELETED";e>0&&(y.value=`任务 ${t} 后端已恢复,继续等待执行结果...`),e=0;const l=ne(t)?.taskStatus||"";if(l==="SUCCESS"||l==="FAILED"||l==="COMPLETED")return l}catch(o){if(!yt(o))throw o;if(e+=1,e>=Lt)throw new Error(`任务 ${t} 等待后端恢复超时,请稍后刷新查看状态`);y.value=`任务 ${t} 执行中,正在等待后端服务恢复(${e}/${Lt})...`}await vt(X())}}async function $t(){if(!(g||H.value)){H.value=!0,F.value=!0,jt();try{const t=Ee();if(!t?.enqueue_json)throw new Error("当前客户端未提供 enqueue_json");if(h.value){const c=await Nt(h.value);y.value=c==="DELETED"?"任务已删除":`任务 ${h.value} ${c==="SUCCESS"?"已完成":"执行失败"}`,E();return}const e=tt.value;if(!e.length){d.warning("请先匹配可用店铺");return}const o=await Bt(()=>De(e.map(ee)),(c,re)=>{y.value=`后端服务暂时不可用,正在重试创建任务(${c}/${re})...`}),n=o.items||[];if(!o.taskId||!n.length||n.some(c=>!c.taskId||!c.resultId))throw new Error("后端未返回有效任务标识");h.value=o.taskId,nt(),Gt(n),R();const l=ae(o.taskId,n);Z.value=JSON.stringify(l,null,2);const s=await t.enqueue_json(l);if(!s?.success){await Pe(o.taskId,{shops:n.map(c=>({shopName:c.shopName||"",error:s?.error||`任务 ${o.taskId} 推送失败`,countrySections:c.countrySections||[],cartRatios:c.cartRatios||[],shopDone:!0,submissionId:xt(o.taskId,c.shopName),chunkIndex:1,chunkTotal:1}))});for(const c of e)ot(c);await J(),y.value=`任务 ${o.taskId} 推送失败`,E();return}for(const c of e)ot(c);y.value=`任务 ${o.taskId} 已入队,共 ${n.length} 个店铺,等待执行完成`;const f=await Nt(o.taskId);y.value=`任务 ${o.taskId} ${f==="SUCCESS"?"已完成":f==="DELETED"?"已删除":"执行失败"}`,E(),await J(),d.success("巡店删除任务已完成")}catch(t){if(g)return;const e=t instanceof Error?t.message:"队列执行失败";y.value=e,d.error(e),await J()}finally{H.value=!1,F.value=!1,it(),nt()}}}async function oe(){const t=tt.value;if(!t.length){d.warning("请先匹配可用店铺");return}y.value=`开始创建任务,共 ${t.length} 个店铺`,await $t()}async function le(t){const e=C(t).find(s=>!!(s.resultId&&(s.fileReady||s.downloadUrl)));if(!e?.resultId)return;const o=Ne(e.resultId),n=e.outputFilename||`${t.shopName||"patrol-delete-result"}.xlsx`,l=await $e(o,n,`patrol-delete:${e.resultId}`);l.success?d.success(`已保存: ${l.path||n}`):l.error&&l.error!=="用户取消"&&d.error(l.error)}async function Rt(t){try{if(t.taskId)await Re(t.taskId),h.value===t.taskId&&E();else if(t.resultId)await Me(t.resultId);else throw new Error("缺少可删除的任务标识");Tt(t),await Promise.allSettled([$(),J()]),d.success("已删除")}catch(e){if(zt(e)){t.taskId&&h.value===t.taskId&&E(),Tt(t),await $(),d.success("后端记录已不存在,已同步移除本地记录");return}d.error(e instanceof Error?e.message:"删除失败")}}return ue(async()=>{Qt(),Kt(),await Promise.all([$(),lt(),R(),rt()]),h.value&&(y.value=h.value!=null?`检测到未完成任务,继续等待任务 ${h.value} 完成`:"",$t())}),ce(()=>{g=!0,it(),qt(),T.clearScope()}),(t,e)=>{const o=fe,n=pe,l=he;return i(),u("div",He,[m(de,{active:"patrol-delete"}),a("div",Oe,[a("aside",Ve,[e[5]||(e[5]=a("div",{class:"section-title"},"店铺输入",-1)),a("div",Qe,[e[3]||(e[3]=a("div",{class:"hint"}," 左侧负责录入店铺并加入备选区,点击“匹配店铺”只会生成匹配结果;确认后需手动点击“推送到 Python 队列”才会创建并执行任务。 ",-1)),a("div",Ke,[m(o,{modelValue:A.value,"onUpdate:modelValue":e[0]||(e[0]=s=>A.value=s),clearable:"",placeholder:"请输入店铺名后回车或点击添加",onKeyup:Mt(Dt,["enter"])},null,8,["modelValue"]),a("button",{type:"button",class:"opt-btn",disabled:B.value,onClick:Dt},r(B.value?"添加中...":"添加"),9,ze)])]),e[6]||(e[6]=a("div",{class:"section-title"},"备选区",-1)),Y.value.length?(i(),u("div",je,[m(l,{data:Y.value,"row-key":"id",height:"260",class:"candidate-table",onSelectionChange:Jt},{default:S(()=>[m(n,{type:"selection",width:"42"}),m(n,{prop:"shop_name",label:"店铺名","min-width":"140","show-overflow-tooltip":""}),m(n,{label:"操作",width:"72",align:"center"},{default:S(({row:s})=>[a("button",{type:"button",class:"link-danger",onClick:f=>Xt(s.id)}," 删除 ",8,Je)]),_:1})]),_:1},8,["data"])])):(i(),u("div",Ge," 暂无备选店铺,请先输入并添加 ")),e[7]||(e[7]=a("div",{class:"section-title condition-title"},[a("span",null,"删除条件"),a("span",{class:"condition-title-hint"}," 注意删除条件的描述需要和页面描述一致 ")],-1)),a("div",We,[a("div",Xe,[m(o,{modelValue:L.value,"onUpdate:modelValue":e[1]||(e[1]=s=>L.value=s),clearable:"",placeholder:"请输入删除条件",onKeyup:Mt(Pt,["enter"])},null,8,["modelValue"]),a("button",{type:"button",class:"opt-btn",disabled:x.value,onClick:Pt},r(x.value?"保存中...":"保存"),9,Ye)]),D.value.length?(i(),u("ul",ts,[(i(!0),u(W,null,ut(D.value,s=>(i(),u("li",{key:s.id,class:"condition-item"},[a("label",es,[me(a("input",{"onUpdate:modelValue":e[2]||(e[2]=f=>_.value=f),type:"checkbox",value:s.id},null,8,ss),[[ve,_.value]]),a("span",{title:s.conditionText},r(s.conditionText),9,as)]),a("button",{type:"button",class:"link-danger",onClick:f=>Wt(s.id)}," 删除 ",8,ns)]))),128))])):(i(),u("div",Ze," 暂无删除条件,保存后可在推送任务时多选携带。 "))]),a("div",os,[a("button",{type:"button",class:"btn-run",disabled:U.value||V.value,onClick:Zt},r(U.value?"匹配中...":"匹配店铺"),9,ls),a("button",{type:"button",class:"btn-run btn-queue",disabled:F.value||!tt.value.length,onClick:oe},r(F.value?"任务执行中...":"推送到 Python 队列"),9,rs)]),e[8]||(e[8]=a("p",{class:"loading-msg"}," 当前页面会把匹配结果合并为一个巡店删除任务推送;多个店铺会在同一个任务和同一个结果文件中汇总。 ",-1)),y.value?(i(),u("div",is,[e[4]||(e[4]=a("div",{class:"section-title queue-debug-title"},"队列状态",-1)),a("div",us,r(y.value),1),Z.value?(i(),u("pre",cs,r(Z.value),1)):v("",!0)])):v("",!0)]),a("section",ds,[e[17]||(e[17]=a("div",{class:"panel-header"},"匹配与任务",-1)),a("div",fs,[a("div",ps,[a("div",hs,[e[9]||(e[9]=a("span",{class:"summary-label"},"备选店铺",-1)),a("strong",null,r(P.value.candidateCount),1)]),a("div",ms,[e[10]||(e[10]=a("span",{class:"summary-label"},"已处理任务",-1)),a("strong",null,r(P.value.processedTaskCount),1)]),a("div",vs,[e[11]||(e[11]=a("span",{class:"summary-label"},"成功任务",-1)),a("strong",null,r(P.value.successTaskCount),1)]),a("div",ys,[e[12]||(e[12]=a("span",{class:"summary-label"},"失败任务",-1)),a("strong",null,r(P.value.failedTaskCount),1)])]),e[16]||(e[16]=a("div",{class:"subsection-title"},"匹配结果",-1)),w.value.length?(i(),ye(l,{key:1,data:w.value,"row-key":N,"highlight-current-row":!1,class:"result-table match-table"},{default:S(()=>[m(n,{prop:"shopName",label:"店铺名","min-width":"120"}),m(n,{label:"匹配",width:"72",align:"center"},{default:S(({row:s})=>[a("span",{class:ct(s.matched?"ok":"fail")},r(s.matched?"是":"否"),3)]),_:1}),m(n,{prop:"shopId",label:"店铺 ID","min-width":"120","show-overflow-tooltip":""}),m(n,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),m(n,{prop:"companyName",label:"公司","min-width":"120","show-overflow-tooltip":""}),m(n,{label:"状态",width:"110","show-overflow-tooltip":""},{default:S(({row:s})=>[At(r(Ut(s.matchStatus)),1)]),_:1}),m(n,{label:"说明","min-width":"180","show-overflow-tooltip":""},{default:S(({row:s})=>[At(r(Ft(s)),1)]),_:1}),m(n,{label:"操作",width:"72",align:"center"},{default:S(({row:s})=>[a("button",{type:"button",class:"link-danger",onClick:f=>te(s)}," 删除 ",8,ws)]),_:1})]),_:1},8,["data"])):(i(),u("div",_s," 完成“匹配店铺”后,这里会展示匹配结果。 ")),a("div",gs,[e[15]||(e[15]=a("div",{class:"result-list-header"},[a("span",null,"任务记录")],-1)),!O.value.length&&!et.value.length?(i(),u("div",ks," 暂无任务记录。推送到 Python 队列后,这里会展示当前任务和历史任务。 ")):(i(),u(W,{key:1},[O.value.length?(i(),u("div",bs,[e[13]||(e[13]=a("div",{class:"result-subsection-title"},"当前任务",-1)),a("ul",Ss,[(i(!0),u(W,null,ut(O.value,s=>(i(),u("li",{key:mt(s),class:"task-item"},[a("div",Is,[a("span",{class:"id",title:K(s)},r(K(s)),9,Ts),a("div",Cs,"任务 ID: "+r(s.taskId??"-"),1),z(s)?(i(),u("div",Es," 结果 ID: "+r(z(s)),1)):v("",!0),G(s)?(i(),u("div",Ds," 店铺 ID: "+r(G(s)),1)):v("",!0),s.platform?(i(),u("div",Ps," 平台: "+r(s.platform),1)):v("",!0),a("div",Ns," 创建时间: "+r(at(s.createdAt)),1),a("div",$s," 模板: "+r(wt(s)),1),j(s)?(i(),u("div",Rs," 错误: "+r(j(s)),1)):v("",!0)]),a("div",Ms,[a("span",{class:ct(["status",bt(s.taskStatus)])},r(kt(s.taskStatus)),3),a("button",{type:"button",class:"btn-delete",onClick:f=>Rt(s)}," 删除 ",8,As)])]))),128))])])):v("",!0),et.value.length?(i(),u("div",Ls,[e[14]||(e[14]=a("div",{class:"result-subsection-title"},"历史任务",-1)),a("ul",qs,[(i(!0),u(W,null,ut(et.value,s=>(i(),u("li",{key:mt(s),class:"task-item"},[a("div",Bs,[a("span",{class:"id",title:K(s)},r(K(s)),9,xs),a("div",Us,"任务 ID: "+r(s.taskId??"-"),1),z(s)?(i(),u("div",Fs," 结果 ID: "+r(z(s)),1)):v("",!0),G(s)?(i(),u("div",Hs," 店铺 ID: "+r(G(s)),1)):v("",!0),s.platform?(i(),u("div",Os," 平台: "+r(s.platform),1)):v("",!0),a("div",Vs," 创建时间: "+r(at(s.createdAt)),1),s.finishedAt?(i(),u("div",Qs," 完成时间: "+r(at(s.finishedAt)),1)):v("",!0),a("div",Ks," 模板: "+r(wt(s)),1),j(s)?(i(),u("div",zs," 错误: "+r(j(s)),1)):v("",!0)]),a("div",Gs,[a("span",{class:ct(["status",bt(s.taskStatus)])},r(kt(s.taskStatus)),3),St(s)?(i(),u("button",{key:0,type:"button",class:"archive",onClick:f=>le(s)}," 下载结果 ",8,js)):v("",!0),a("button",{type:"button",class:"btn-delete",onClick:f=>Rt(s)}," 删除 ",8,Js)])]))),128))])])):v("",!0)],64))])])])])])}}}),Xs=Le(Ws,[["__scopeId","data-v-09e791f5"]]);qe.locale("zh-cn");Be(Xs).use(xe,{locale:Ue}).mount("#app"); +import{d as ie,o as ue,M as ce,a as i,c as u,b as m,B as de,e as a,ad as Mt,ae as fe,t as r,af as S,ag as pe,ah as he,F as W,r as ut,w as me,v as ve,f as v,ak as ye,n as ct,y as At,g as p,h as M,b9 as _e,ba as we,bb as ge,bc as ke,E as d,bd as be,be as Se,bf as Ie,bg as Te,bh as Ce,i as Ee,bi as De,bj as Pe,bk as Ne,s as $e,bl as Re,bm as Me,V as X,bn as Ae,_ as Le,aQ as qe,q as Be,u as xe}from"./java-modules-B8c-YG5x.js";import{z as Ue}from"./zh-cn-CscLo6na.js";/* empty css */import{c as Fe}from"./categorized-timers-JPA-olTr.js";const He={class:"page-shell module-page"},Oe={class:"main-content"},Ve={class:"left-panel"},Qe={class:"input-zone"},Ke={class:"input-row"},ze=["disabled"],Ge={key:0,class:"empty-candidates"},je={key:1,class:"candidate-table-scroll"},Je=["onClick"],We={class:"condition-panel"},Xe={class:"condition-input-row"},Ye=["disabled"],Ze={key:0,class:"empty-conditions"},ts={key:1,class:"condition-list"},es={class:"condition-check"},ss=["value"],as=["title"],ns=["onClick"],os={class:"run-row"},ls=["disabled"],rs=["disabled"],is={key:2,class:"queue-debug-card"},us={class:"queue-debug-line"},cs={key:0,class:"queue-debug-payload"},ds={class:"right-panel"},fs={class:"task-list-wrap"},ps={class:"clean-result-summary"},hs={class:"summary-card"},ms={class:"summary-card"},vs={class:"summary-card"},ys={class:"summary-card"},_s={key:0,class:"empty-tasks narrow"},ws=["onClick"],gs={class:"result-list-wrap"},ks={key:0,class:"empty-tasks"},bs={key:0,class:"result-subsection"},Ss={class:"task-list"},Is={class:"left split-result-main"},Ts=["title"],Cs={class:"files"},Es={key:0,class:"files"},Ds={key:1,class:"files"},Ps={key:2,class:"files"},Ns={class:"files"},$s={class:"files"},Rs={key:3,class:"files"},Ms={class:"task-right"},As=["onClick"],Ls={key:1,class:"result-subsection"},qs={class:"task-list"},Bs={class:"left split-result-main"},xs=["title"],Us={class:"files"},Fs={key:0,class:"files"},Hs={key:1,class:"files"},Os={key:2,class:"files"},Vs={class:"files"},Qs={key:3,class:"files"},Ks={class:"files"},zs={key:4,class:"files"},Gs={class:"task-right"},js=["onClick"],Js=["onClick"],Lt=30,Ws=ie({__name:"BrandPatrolDeleteTab",setup(Ys){const dt=["德国","英国","法国","意大利","西班牙"],A=p(""),L=p(""),Y=p([]),q=p([]),D=p([]),_=p([]),w=p([]),k=p([]),P=p({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),B=p(!1),x=p(!1),U=p(!1),F=p(!1),y=p(""),Z=p(""),h=p(null),H=p(!1);let I=null;const T=Fe("patrol-delete"),tt=M(()=>w.value.filter(t=>t.matched)),ft=M(()=>Vt(k.value)),O=M(()=>ft.value.filter(t=>!gt(t.taskStatus))),et=M(()=>ft.value.filter(t=>gt(t.taskStatus))),V=M(()=>H.value||!!h.value);function st(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function pt(){return`patrol-delete:matched:${st()}`}function ht(){return`patrol-delete:queue-state:${st()}`}function N(t){return`${(t.shopName||"").trim()}::${t.shopId||""}`}function Q(t){return`${t.taskId??0}:${t.resultId??0}`}function mt(t){return`task:${t.taskId??t.resultId??0}`}let g=!1;function vt(t){return g?Promise.resolve():T.sleep("queue-wait",t)}function qt(){T.clearCategory("queue-wait")}function yt(t){const e=t instanceof Error?t.message.toLowerCase():String(t||"").toLowerCase();return e.includes("network error")||e.includes("failed to fetch")||e.includes("timeout")||e.includes("503")||e.includes("502")||e.includes("504")||e.includes("500")||e.includes("load failed")}async function Bt(t,e,o=20){let n=0;for(;;){if(g)throw new Error("component disposed");try{return await t()}catch(l){if(!yt(l)||n>=o-1)throw l;n+=1,e?.(n,o),await vt(X())}}}function xt(t,e){return`patrol-delete:${t}:${e||"shop"}:${Date.now()}`}function at(t){if(!t)return"-";const e=new Date(t);if(Number.isNaN(e.getTime()))return t;const o=e.getFullYear(),n=String(e.getMonth()+1).padStart(2,"0"),l=String(e.getDate()).padStart(2,"0"),s=String(e.getHours()).padStart(2,"0"),f=String(e.getMinutes()).padStart(2,"0"),c=String(e.getSeconds()).padStart(2,"0");return`${o}-${n}-${l} ${s}:${f}:${c}`}function Ut(t){const e=(t||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[e]||e||"-"}function Ft(t){const e=(t.matchMessage||"").trim();return e||(t.matched&&t.matchStatus==="MATCHED"?"索引已命中,可推送到 Python 队列":t.matched?"已命中索引,请结合状态列确认":"未命中或未就绪,请检查店铺名")}function Ht(){return dt.map(t=>({country:t,rows:[{status:"全部",quantity:"",deleteQuantity:"",processStatus:""}]}))}function Ot(){return dt.map(t=>({country:t,ratio:""}))}function _t(t){const e=t.countrySections||[],o=t.cartRatios||[],n=Math.max(...e.map(l=>l.rows.length),1);return Array.from({length:n},(l,s)=>({shopName:s===0?t.shopName:"",countries:e.map(f=>{const c=f.rows[s];return{country:f.country,status:c?.status||"",quantity:c?.quantity||"",deleteQuantity:c?.deleteQuantity||"",processStatus:c?.processStatus||""}}),cartRatios:s===0?o.map(f=>({country:f.country,ratio:f.ratio})):[]}))}function wt(t){return`${new Set([...(t.countrySections||[]).map(o=>o.country).filter(Boolean),...(t.cartRatios||[]).map(o=>o.country).filter(Boolean)]).size||0} 个国家,含状态数据和购物车比例`}function b(t){return Array.from(new Set(t.map(e=>e==null?"":String(e).trim()).filter(Boolean))).join("、")}function Vt(t){const e=new Map;for(const o of t||[]){const n=String(o.taskId??`result:${o.resultId??Math.random()}`),l=e.get(n)||[];l.push(o),e.set(n,l)}return Array.from(e.values()).map(o=>{const n=o.find(s=>St(s))||o.find(s=>s.taskStatus)||o[0],l=b(o.map(s=>s.error));return{...n,shopName:b(o.map(s=>s.shopName))||n.shopName,shopId:b(o.map(s=>s.shopId))||n.shopId,error:l||n.error,__groupItems:o}})}function C(t){return t.__groupItems||[t]}function K(t){return b(C(t).map(e=>e.shopName))||"-"}function z(t){return b(C(t).map(e=>e.resultId))}function G(t){return b(C(t).map(e=>e.shopId))}function j(t){return b(C(t).map(e=>e.error))}function gt(t){return t==="SUCCESS"||t==="FAILED"||t==="COMPLETED"}function kt(t){return t==="SUCCESS"||t==="COMPLETED"?"已完成":t==="FAILED"?"失败":"执行中"}function bt(t){return t==="SUCCESS"||t==="COMPLETED"?"success":t==="FAILED"?"failed":"running"}function St(t){return C(t).some(e=>!!(e.resultId&&(e.fileReady||e.downloadUrl)))}function It(){typeof window>"u"||window.localStorage.setItem(pt(),JSON.stringify(w.value))}function Qt(){try{const t=typeof window<"u"?window.localStorage.getItem(pt()):null;w.value=t?JSON.parse(t):[]}catch{w.value=[]}}function nt(){if(typeof window>"u")return;const t={activeTaskId:h.value};window.localStorage.setItem(ht(),JSON.stringify(t))}function Kt(){try{const t=typeof window<"u"?window.localStorage.getItem(ht()):null;if(!t)return;const e=JSON.parse(t);h.value=e.activeTaskId??null}catch{h.value=null}}function E(){h.value=null,nt()}function zt(t){const e=t instanceof Error?t.message:String(t||"");return/记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(e)}function ot(t){const e=N(t);w.value=w.value.filter(o=>N(o)!==e),It()}function Tt(t){k.value=k.value.filter(e=>!(t.resultId!=null&&e.resultId===t.resultId||t.taskId!=null&&e.taskId===t.taskId))}async function $(){Y.value=await _e()}async function lt(){D.value=await we();const t=new Set(D.value.map(e=>e.id));_.value=_.value.filter(e=>t.has(e))}async function R(){P.value=await ge()}async function rt(){const t=await ke();k.value=t.items||[]}async function J(){await Promise.all([R(),rt()])}function Ct(t){if(!t.length)return;const e=new Map(t.map(n=>[Q(n),n])),o=k.value.map(n=>{const l=e.get(Q(n));return l?{...n,...l,countrySections:l.countrySections||n.countrySections||[],cartRatios:l.cartRatios||n.cartRatios||[]}:n});for(const n of t){const l=Q(n);o.some(s=>Q(s)===l)||o.push(n)}k.value=o}function Gt(t){Ct(t)}async function Et(t){const e=Array.from(new Set((t&&t.length?t:O.value.map(n=>n.taskId??0)).filter(n=>Number.isFinite(n)&&n>0)));if(!e.length)return[];const o=await Ae(e);return Ct(o.items||[]),(o.missingTaskIds||[]).length&&await rt(),o.missingTaskIds||[]}function jt(){if(it(),g||!V.value)return;const t=async()=>{I=null,!(g||!V.value)&&(await Et(),!g&&V.value&&(I=T.setTimeout("history-poll",t,X()*2)))};I=T.setTimeout("history-poll",t,X()*2)}function it(){I&&(T.clearTimer("history-poll",I),I=null)}function Jt(t){q.value=t}async function Dt(){const t=A.value.trim();if(!t){d.warning("请输入店铺名");return}B.value=!0;try{await be(t),A.value="",await Promise.all([$(),R()]),d.success("已加入备选区")}catch(e){d.error(e instanceof Error?e.message:"添加失败")}finally{B.value=!1}}async function Pt(){const t=L.value.trim();if(!t){d.warning("请输入删除条件");return}x.value=!0;try{const e=await Se(t);L.value="",await lt(),e?.id&&!_.value.includes(e.id)&&(_.value=[..._.value,e.id]),d.success("删除条件已保存")}catch(e){d.error(e instanceof Error?e.message:"保存失败")}finally{x.value=!1}}async function Wt(t){try{await Ie(t),_.value=_.value.filter(e=>e!==t),await lt(),d.success("删除条件已删除")}catch(e){d.error(e instanceof Error?e.message:"删除失败")}}async function Xt(t){try{await Te(t),q.value=q.value.filter(e=>e.id!==t),await Promise.all([$(),R()]),d.success("已删除")}catch(e){d.error(e instanceof Error?e.message:"删除失败")}}function Yt(t,e){const o=new Map;for(const n of t)o.set(N(n),n);for(const n of e)o.set(N(n),n);return Array.from(o.values())}async function Zt(){const t=q.value.map(e=>e.shop_name).filter(Boolean);if(!t.length){d.warning("请先勾选备选区店铺");return}U.value=!0;try{const e=await Ce(t);w.value=Yt(w.value,e.items||[]),It(),d.success(`本次返回 ${e.items?.length||0} 条匹配结果`)}catch(e){d.error(e instanceof Error?e.message:"匹配失败")}finally{U.value=!1}}function te(t){ot(t),d.success("已从匹配结果移除")}function ee(t){return{shopName:t.shopName,matched:t.matched,shopId:t.shopId,platform:t.platform,companyName:t.companyName,matchStatus:t.matchStatus,matchMessage:t.matchMessage,countrySections:Ht(),cartRatios:Ot()}}function se(){const t=new Set(_.value);return D.value.filter(e=>t.has(e.id)).map(e=>({id:e.id,conditionText:e.conditionText}))}function ae(t,e){const o=e[0],n=se();return{type:"patrol-delete-run",ts:Date.now(),data:{taskId:t,user_id:Number(st())||0,source:"frontend-vue-patrol-delete",delete_conditions:n,deleteConditions:n,items:e.map(l=>({shopName:l.shopName,shopId:l.shopId,platform:l.platform,companyName:l.companyName,matched:l.matched,matchStatus:l.matchStatus,matchMessage:l.matchMessage,countrySections:l.countrySections||[],cartRatios:l.cartRatios||[]})),template_rows:o?_t(o):[],shop_template_rows:e.map(l=>({shopName:l.shopName,shopId:l.shopId,templateRows:_t(l)})),country_sections:o?.countrySections||[],cart_ratios:o?.cartRatios||[]}}}function ne(t){return k.value.find(e=>e.taskId===t)}async function Nt(t){let e=0;for(;;){if(g)return"STOPPED";if(h.value!==t)return"DELETED";try{if((await Et([t])).includes(t))return E(),"DELETED";if(h.value!==t)return"DELETED";e>0&&(y.value=`任务 ${t} 后端已恢复,继续等待执行结果...`),e=0;const l=ne(t)?.taskStatus||"";if(l==="SUCCESS"||l==="FAILED"||l==="COMPLETED")return l}catch(o){if(!yt(o))throw o;if(e+=1,e>=Lt)throw new Error(`任务 ${t} 等待后端恢复超时,请稍后刷新查看状态`);y.value=`任务 ${t} 执行中,正在等待后端服务恢复(${e}/${Lt})...`}await vt(X())}}async function $t(){if(!(g||H.value)){H.value=!0,F.value=!0,jt();try{const t=Ee();if(!t?.enqueue_json)throw new Error("当前客户端未提供 enqueue_json");if(h.value){const c=await Nt(h.value);y.value=c==="DELETED"?"任务已删除":`任务 ${h.value} ${c==="SUCCESS"?"已完成":"执行失败"}`,E();return}const e=tt.value;if(!e.length){d.warning("请先匹配可用店铺");return}const o=await Bt(()=>De(e.map(ee)),(c,re)=>{y.value=`后端服务暂时不可用,正在重试创建任务(${c}/${re})...`}),n=o.items||[];if(!o.taskId||!n.length||n.some(c=>!c.taskId||!c.resultId))throw new Error("后端未返回有效任务标识");h.value=o.taskId,nt(),Gt(n),R();const l=ae(o.taskId,n);Z.value=JSON.stringify(l,null,2);const s=await t.enqueue_json(l);if(!s?.success){await Pe(o.taskId,{shops:n.map(c=>({shopName:c.shopName||"",error:s?.error||`任务 ${o.taskId} 推送失败`,countrySections:c.countrySections||[],cartRatios:c.cartRatios||[],shopDone:!0,submissionId:xt(o.taskId,c.shopName),chunkIndex:1,chunkTotal:1}))});for(const c of e)ot(c);await J(),y.value=`任务 ${o.taskId} 推送失败`,E();return}for(const c of e)ot(c);y.value=`任务 ${o.taskId} 已入队,共 ${n.length} 个店铺,等待执行完成`;const f=await Nt(o.taskId);y.value=`任务 ${o.taskId} ${f==="SUCCESS"?"已完成":f==="DELETED"?"已删除":"执行失败"}`,E(),await J(),d.success("巡店删除任务已完成")}catch(t){if(g)return;const e=t instanceof Error?t.message:"队列执行失败";y.value=e,d.error(e),await J()}finally{H.value=!1,F.value=!1,it(),nt()}}}async function oe(){const t=tt.value;if(!t.length){d.warning("请先匹配可用店铺");return}y.value=`开始创建任务,共 ${t.length} 个店铺`,await $t()}async function le(t){const e=C(t).find(s=>!!(s.resultId&&(s.fileReady||s.downloadUrl)));if(!e?.resultId)return;const o=Ne(e.resultId),n=e.outputFilename||`${t.shopName||"patrol-delete-result"}.xlsx`,l=await $e(o,n,`patrol-delete:${e.resultId}`);l.success?d.success(`已保存: ${l.path||n}`):l.error&&l.error!=="用户取消"&&d.error(l.error)}async function Rt(t){try{if(t.taskId)await Re(t.taskId),h.value===t.taskId&&E();else if(t.resultId)await Me(t.resultId);else throw new Error("缺少可删除的任务标识");Tt(t),await Promise.allSettled([$(),J()]),d.success("已删除")}catch(e){if(zt(e)){t.taskId&&h.value===t.taskId&&E(),Tt(t),await $(),d.success("后端记录已不存在,已同步移除本地记录");return}d.error(e instanceof Error?e.message:"删除失败")}}return ue(async()=>{Qt(),Kt(),await Promise.all([$(),lt(),R(),rt()]),h.value&&(y.value=h.value!=null?`检测到未完成任务,继续等待任务 ${h.value} 完成`:"",$t())}),ce(()=>{g=!0,it(),qt(),T.clearScope()}),(t,e)=>{const o=fe,n=pe,l=he;return i(),u("div",He,[m(de,{active:"patrol-delete"}),a("div",Oe,[a("aside",Ve,[e[5]||(e[5]=a("div",{class:"section-title"},"店铺输入",-1)),a("div",Qe,[e[3]||(e[3]=a("div",{class:"hint"}," 左侧负责录入店铺并加入备选区,点击“匹配店铺”只会生成匹配结果;确认后需手动点击“推送到 Python 队列”才会创建并执行任务。 ",-1)),a("div",Ke,[m(o,{modelValue:A.value,"onUpdate:modelValue":e[0]||(e[0]=s=>A.value=s),clearable:"",placeholder:"请输入店铺名后回车或点击添加",onKeyup:Mt(Dt,["enter"])},null,8,["modelValue"]),a("button",{type:"button",class:"opt-btn",disabled:B.value,onClick:Dt},r(B.value?"添加中...":"添加"),9,ze)])]),e[6]||(e[6]=a("div",{class:"section-title"},"备选区",-1)),Y.value.length?(i(),u("div",je,[m(l,{data:Y.value,"row-key":"id",height:"260",class:"candidate-table",onSelectionChange:Jt},{default:S(()=>[m(n,{type:"selection",width:"42"}),m(n,{prop:"shop_name",label:"店铺名","min-width":"140","show-overflow-tooltip":""}),m(n,{label:"操作",width:"72",align:"center"},{default:S(({row:s})=>[a("button",{type:"button",class:"link-danger",onClick:f=>Xt(s.id)}," 删除 ",8,Je)]),_:1})]),_:1},8,["data"])])):(i(),u("div",Ge," 暂无备选店铺,请先输入并添加 ")),e[7]||(e[7]=a("div",{class:"section-title condition-title"},[a("span",null,"删除条件"),a("span",{class:"condition-title-hint"}," 注意删除条件的描述需要和页面描述一致 ")],-1)),a("div",We,[a("div",Xe,[m(o,{modelValue:L.value,"onUpdate:modelValue":e[1]||(e[1]=s=>L.value=s),clearable:"",placeholder:"请输入删除条件",onKeyup:Mt(Pt,["enter"])},null,8,["modelValue"]),a("button",{type:"button",class:"opt-btn",disabled:x.value,onClick:Pt},r(x.value?"保存中...":"保存"),9,Ye)]),D.value.length?(i(),u("ul",ts,[(i(!0),u(W,null,ut(D.value,s=>(i(),u("li",{key:s.id,class:"condition-item"},[a("label",es,[me(a("input",{"onUpdate:modelValue":e[2]||(e[2]=f=>_.value=f),type:"checkbox",value:s.id},null,8,ss),[[ve,_.value]]),a("span",{title:s.conditionText},r(s.conditionText),9,as)]),a("button",{type:"button",class:"link-danger",onClick:f=>Wt(s.id)}," 删除 ",8,ns)]))),128))])):(i(),u("div",Ze," 暂无删除条件,保存后可在推送任务时多选携带。 "))]),a("div",os,[a("button",{type:"button",class:"btn-run",disabled:U.value||V.value,onClick:Zt},r(U.value?"匹配中...":"匹配店铺"),9,ls),a("button",{type:"button",class:"btn-run btn-queue",disabled:F.value||!tt.value.length,onClick:oe},r(F.value?"任务执行中...":"推送到 Python 队列"),9,rs)]),e[8]||(e[8]=a("p",{class:"loading-msg"}," 当前页面会把匹配结果合并为一个巡店删除任务推送;多个店铺会在同一个任务和同一个结果文件中汇总。 ",-1)),y.value?(i(),u("div",is,[e[4]||(e[4]=a("div",{class:"section-title queue-debug-title"},"队列状态",-1)),a("div",us,r(y.value),1),Z.value?(i(),u("pre",cs,r(Z.value),1)):v("",!0)])):v("",!0)]),a("section",ds,[e[17]||(e[17]=a("div",{class:"panel-header"},"匹配与任务",-1)),a("div",fs,[a("div",ps,[a("div",hs,[e[9]||(e[9]=a("span",{class:"summary-label"},"备选店铺",-1)),a("strong",null,r(P.value.candidateCount),1)]),a("div",ms,[e[10]||(e[10]=a("span",{class:"summary-label"},"已处理任务",-1)),a("strong",null,r(P.value.processedTaskCount),1)]),a("div",vs,[e[11]||(e[11]=a("span",{class:"summary-label"},"成功任务",-1)),a("strong",null,r(P.value.successTaskCount),1)]),a("div",ys,[e[12]||(e[12]=a("span",{class:"summary-label"},"失败任务",-1)),a("strong",null,r(P.value.failedTaskCount),1)])]),e[16]||(e[16]=a("div",{class:"subsection-title"},"匹配结果",-1)),w.value.length?(i(),ye(l,{key:1,data:w.value,"row-key":N,"highlight-current-row":!1,class:"result-table match-table"},{default:S(()=>[m(n,{prop:"shopName",label:"店铺名","min-width":"120"}),m(n,{label:"匹配",width:"72",align:"center"},{default:S(({row:s})=>[a("span",{class:ct(s.matched?"ok":"fail")},r(s.matched?"是":"否"),3)]),_:1}),m(n,{prop:"shopId",label:"店铺 ID","min-width":"120","show-overflow-tooltip":""}),m(n,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),m(n,{prop:"companyName",label:"公司","min-width":"120","show-overflow-tooltip":""}),m(n,{label:"状态",width:"110","show-overflow-tooltip":""},{default:S(({row:s})=>[At(r(Ut(s.matchStatus)),1)]),_:1}),m(n,{label:"说明","min-width":"180","show-overflow-tooltip":""},{default:S(({row:s})=>[At(r(Ft(s)),1)]),_:1}),m(n,{label:"操作",width:"72",align:"center"},{default:S(({row:s})=>[a("button",{type:"button",class:"link-danger",onClick:f=>te(s)}," 删除 ",8,ws)]),_:1})]),_:1},8,["data"])):(i(),u("div",_s," 完成“匹配店铺”后,这里会展示匹配结果。 ")),a("div",gs,[e[15]||(e[15]=a("div",{class:"result-list-header"},[a("span",null,"任务记录")],-1)),!O.value.length&&!et.value.length?(i(),u("div",ks," 暂无任务记录。推送到 Python 队列后,这里会展示当前任务和历史任务。 ")):(i(),u(W,{key:1},[O.value.length?(i(),u("div",bs,[e[13]||(e[13]=a("div",{class:"result-subsection-title"},"当前任务",-1)),a("ul",Ss,[(i(!0),u(W,null,ut(O.value,s=>(i(),u("li",{key:mt(s),class:"task-item"},[a("div",Is,[a("span",{class:"id",title:K(s)},r(K(s)),9,Ts),a("div",Cs,"任务 ID: "+r(s.taskId??"-"),1),z(s)?(i(),u("div",Es," 结果 ID: "+r(z(s)),1)):v("",!0),G(s)?(i(),u("div",Ds," 店铺 ID: "+r(G(s)),1)):v("",!0),s.platform?(i(),u("div",Ps," 平台: "+r(s.platform),1)):v("",!0),a("div",Ns," 创建时间: "+r(at(s.createdAt)),1),a("div",$s," 模板: "+r(wt(s)),1),j(s)?(i(),u("div",Rs," 错误: "+r(j(s)),1)):v("",!0)]),a("div",Ms,[a("span",{class:ct(["status",bt(s.taskStatus)])},r(kt(s.taskStatus)),3),a("button",{type:"button",class:"btn-delete",onClick:f=>Rt(s)}," 删除 ",8,As)])]))),128))])])):v("",!0),et.value.length?(i(),u("div",Ls,[e[14]||(e[14]=a("div",{class:"result-subsection-title"},"历史任务",-1)),a("ul",qs,[(i(!0),u(W,null,ut(et.value,s=>(i(),u("li",{key:mt(s),class:"task-item"},[a("div",Bs,[a("span",{class:"id",title:K(s)},r(K(s)),9,xs),a("div",Us,"任务 ID: "+r(s.taskId??"-"),1),z(s)?(i(),u("div",Fs," 结果 ID: "+r(z(s)),1)):v("",!0),G(s)?(i(),u("div",Hs," 店铺 ID: "+r(G(s)),1)):v("",!0),s.platform?(i(),u("div",Os," 平台: "+r(s.platform),1)):v("",!0),a("div",Vs," 创建时间: "+r(at(s.createdAt)),1),s.finishedAt?(i(),u("div",Qs," 完成时间: "+r(at(s.finishedAt)),1)):v("",!0),a("div",Ks," 模板: "+r(wt(s)),1),j(s)?(i(),u("div",zs," 错误: "+r(j(s)),1)):v("",!0)]),a("div",Gs,[a("span",{class:ct(["status",bt(s.taskStatus)])},r(kt(s.taskStatus)),3),St(s)?(i(),u("button",{key:0,type:"button",class:"archive",onClick:f=>le(s)}," 下载结果 ",8,js)):v("",!0),a("button",{type:"button",class:"btn-delete",onClick:f=>Rt(s)}," 删除 ",8,Js)])]))),128))])])):v("",!0)],64))])])])])])}}}),Xs=Le(Ws,[["__scopeId","data-v-09e791f5"]]);qe.locale("zh-cn");Be(Xs).use(xe,{locale:Ue}).mount("#app"); diff --git a/app/assets/price-track.js b/app/assets/price-track.js index 3e939dd..577b922 100644 --- a/app/assets/price-track.js +++ b/app/assets/price-track.js @@ -1 +1 @@ -import{d as es,o as ts,M as ss,a as i,c,b as C,B as as,e as n,w as ct,x as dt,aR as ns,f as y,F as L,y as ve,r as fe,t as v,ad as os,ae as ls,af as z,ag as rs,ah as us,ai as vt,n as _e,ak as is,g as f,h as q,i as pe,E as r,aS as cs,aT as ds,aU as vs,aV as fs,aW as ps,aX as ms,aY as hs,aZ as ys,a_ as ks,a$ as ft,b0 as gs,b1 as ws,b2 as _s,b3 as bs,b4 as Is,V as Ss,b5 as Cs,s as Ts,b6 as Ns,b7 as Es,b8 as pt,_ as Ps,q as As,u as Rs}from"./java-modules-DzYrjxib.js";/* empty css */import{e as xs}from"./brand-jr47vQUd.js";import{c as Ms}from"./categorized-timers-JPA-olTr.js";const $s={class:"page-shell module-page"},Ds={class:"main-content"},Ls={class:"left-panel"},Fs={class:"mode-zone"},Us={class:"mode-check-row"},Bs=["checked"],Os={class:"mode-check-row"},qs=["checked"],js={class:"mode-zone"},Js={class:"mode-check-row"},Ks={class:"mode-check-row"},Vs={key:0,class:"loop-round-input"},Ws={class:"upload-zone"},Hs={class:"selected-files clean-placeholder"},zs={key:1,class:"text-muted"},Gs={class:"input-zone"},Qs={class:"input-row"},Xs=["disabled"],Ys={key:0,class:"empty-candidates"},Zs={key:1,class:"candidate-table-scroll"},ea=["onClick"],ta={class:"country-pref-checks"},sa=["checked","disabled","onChange"],aa={class:"country-check-text"},na={key:0,class:"country-order-panel"},oa={class:"country-order-list"},la=["onDragstart","onDrop"],ra={class:"country-drag-label"},ua={key:1,class:"country-pref-status"},ia={key:3,class:"mode-status-bar"},ca={class:"run-row"},da=["disabled"],va=["disabled"],fa={key:4,class:"loop-status-card"},pa={class:"loop-status-line"},ma={class:"loop-status-line"},ha={class:"loop-status-line"},ya={class:"loop-status-line"},ka={key:0,class:"loop-status-line loop-error"},ga=["disabled"],wa={key:5,class:"queue-debug-card"},_a={class:"queue-debug-line"},ba={key:0,class:"queue-debug-payload"},Ia={class:"right-panel"},Sa={class:"task-list-wrap"},Ca={class:"clean-result-summary pr-summary"},Ta={class:"summary-card"},Na={class:"summary-card"},Ea={class:"summary-card"},Pa={class:"summary-card"},Aa={key:0,class:"empty-tasks narrow"},Ra=["onClick"],xa={class:"result-list-wrap"},Ma={key:0,class:"empty-tasks"},$a={key:0,class:"result-subsection"},Da={class:"task-list clean-result-list"},La={class:"left split-result-main"},Fa={key:0,class:"files"},Ua=["title"],Ba={class:"files"},Oa={key:1,class:"files"},qa={key:2,class:"files"},ja={class:"task-right split-result-actions"},Ja=["onClick"],Ka=["onClick"],Va={key:1,class:"result-subsection"},Wa={class:"task-list clean-result-list"},Ha={class:"left split-result-main"},za={key:0,class:"files"},Ga=["title"],Qa={class:"files"},Xa={key:1,class:"files"},Ya={key:2,class:"files"},Za={class:"task-right split-result-actions"},en=["onClick"],tn=["onClick"],sn=es({__name:"BrandPriceTrackTab",setup(nn){const be=[{code:"DE",label:"德国"},{code:"UK",label:"英国"},{code:"FR",label:"法国"},{code:"IT",label:"意大利"},{code:"ES",label:"西班牙"}],te=f(""),Ie=f([]),qe=f([]),I=f([]),me=f(!1),he=f(!1),j=f(!1),Se=f(!1),je=f(!1),p=f(""),G=f(""),Ce=f({}),J=f("FINITE"),ye=f(1),m=f(null),k=f(null),Te=f(!1),se=f(!1),A=f(!0),S=f(!1),R=f([]),ae=f([]),Ne=q(()=>A.value||S.value),mt=q(()=>{const e=k.value?.status||"";return e==="SUCCESS"||e==="FAILED"||e==="STOPPED"}),Ee=q(()=>!!m.value&&!mt.value),ht=q(()=>{const e=k.value;if(!e)return"";const t=e.currentRound||1;if(e.executionMode==="INFINITE")return`第 ${t} 轮(无限)`;const s=Math.max(1,e.targetRounds||ye.value||1);return`第 ${t}/${s} 轮`}),g=f(["DE","UK","FR","IT","ES"]),ne=f(null),Pe=f(!1),Je=f(!1);let Q=null;const oe=f({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),K=f([]),w=f([]),N=f({}),_=f({}),M=f(null),Ae=f(!1);let b=!1;const x=Ms("price-track");function X(e){return b?Promise.resolve():x.sleep("queue-wait",e)}function yt(){x.clearCategory("queue-wait")}function le(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function Ke(){return`price-track:tasks:${le()}`}function Ve(){return`price-track:task-status:${le()}`}function We(){return`price-track:tasks-batch-snapshot:${le()}`}function He(){return`price-track:matched-items:${le()}`}function ze(){return`price-track:active-loop:${le()}`}function re(e,t,s){if(!(typeof window>"u"))try{s?window.localStorage.removeItem(e):window.localStorage.setItem(e,JSON.stringify(t))}catch{}}function kt(){try{const e=typeof window<"u"?window.localStorage.getItem(Ke()):null;if(!e){w.value=[];return}const t=JSON.parse(e);w.value=Array.isArray(t)?t.filter(s=>typeof s=="number"&&s>0):[]}catch{w.value=[]}}function Ge(){re(Ke(),w.value,w.value.length===0)}function gt(){try{const e=typeof window<"u"?window.localStorage.getItem(Ve()):null;if(!e)return;const t=JSON.parse(e),s={};for(const[o,l]of Object.entries(t)){const u=Number(o);u>0&&typeof l=="string"&&(s[u]=l)}N.value=s}catch{}}function ue(){re(Ve(),N.value,Object.keys(N.value).length===0)}function wt(){try{const e=typeof window<"u"?window.localStorage.getItem(We()):null;if(!e)return;const t=JSON.parse(e),s={};for(const[o,l]of Object.entries(t)){const u=Number(o);u>0&&l&&typeof l=="object"&&(s[u]=l)}_.value=s}catch{}}function ie(){re(We(),_.value,Object.keys(_.value).length===0)}function _t(){try{const e=typeof window<"u"?window.localStorage.getItem(He()):null;if(!e)return;const t=JSON.parse(e);Array.isArray(t)&&(I.value=t)}catch{}}function ke(){re(He(),I.value,I.value.length===0)}function bt(){try{const e=typeof window<"u"?window.localStorage.getItem(ze()):null;if(!e){m.value=null;return}const t=Number(JSON.parse(e));m.value=Number.isFinite(t)&&t>0?t:null}catch{m.value=null}}function Y(){re(ze(),m.value,!m.value)}async function It(){const e=pe();if(e?.select_files){const t=await e.select_files({filters:[{name:"Excel/CSV",extensions:"xlsx,xls,csv"}],multiple:!0});t?.paths?.length&&(R.value=t.paths,ae.value=await Re(t.paths),r.success(`已选择 ${t.paths.length} 个ASIN文件`));return}if(e?.select_brand_xlsx_files){const t=await e.select_brand_xlsx_files();if(!t?.length)return;R.value=t,ae.value=await Re(t),r.success(`已选择 ${t.length} 个ASIN文件`);return}r.warning("当前环境不支持文件选择,请在本地客户端中打开")}async function St(){const e=pe();if(!e?.select_brand_folder){r.warning("当前环境不支持文件夹选择,请在本地客户端中打开");return}try{const t=await e.select_brand_folder();if(!t)return;const s=await xs(t);if(!s.success||!s.items?.length){r.warning(s.error||"该文件夹下没有可用的 xlsx 文件");return}R.value=s.items.map(o=>o.relativePath||o.absolutePath),ae.value=await Re(s.items),r.success(`已选择文件夹内 ${s.items.length} 个ASIN文件`)}catch(t){r.error(t instanceof Error?t.message:"选择失败")}}async function Re(e){const t=pe();if(!t?.upload_file_to_java)return[];const s=[];for(const o of e){const l=typeof o=="string"?o:o.absolutePath,u=typeof o=="string"?void 0:o.relativePath,a=await t.upload_file_to_java(l,u);if(!a?.success||!a.data)throw new Error(a?.error||a?.message||`上传失败:${l}`);s.push(a.data)}return s}function xe(){return ae.value.length?ae.value.map(e=>e.localPath).filter(e=>!!e):R.value}function ge(){return S.value?be.map(e=>e.code):[...g.value]}function Me(e){A.value=e==="status",S.value=e==="asin"}function Qe(e){return be.find(s=>s.code===e)?.label??e}const Ct=q(()=>{const e=g.value,t=new Set(e),s=e.map(l=>({code:l,label:Qe(l)})),o=be.filter(l=>!t.has(l.code)).map(l=>({code:l.code,label:l.label}));return[...s,...o]});function Tt(e){return g.value.includes(e)}function Xe(e){return g.value.length===1&&g.value[0]===e}function Nt(e,t){const s=t.target;if(s){if(!s.checked&&Xe(e)){s.checked=!0,r.warning("至少保留 1 个国家");return}Et(e,s.checked)}}function Et(e,t){if(Je.value=!0,t)g.value.includes(e)||(g.value=[...g.value,e]);else{if(g.value.length<=1){r.warning("至少保留 1 个国家");return}g.value=g.value.filter(s=>s!==e)}Ye()}function Pt(e){ne.value=e}function At(){ne.value=null}function Rt(e){const t=ne.value;if(ne.value=null,t==null||t===e)return;Je.value=!0;const s=[...g.value],[o]=s.splice(t,1);s.splice(e,0,o),g.value=s,Ye()}function Ye(){Q&&x.clearTimer("preference-save",Q),Q=x.setTimeout("preference-save",()=>{Q=null,xt()},450)}async function xt(){if(!(g.value.length<1)){Pe.value=!0;try{await cs(g.value)}catch(e){r.error(e instanceof Error?e.message:"保存国家顺序失败")}finally{Pe.value=!1}}}async function Mt(){try{const e=await ds();e?.countryCodes?.length&&(g.value=[...e.countryCodes])}catch{}}async function $e(){try{Ie.value=await vs()}catch(e){r.error(e instanceof Error?e.message:"加载备选失败")}}async function $(){try{oe.value=await fs()}catch{}}async function F(){try{const e=await ps();K.value=e.items||[]}catch{K.value=[]}}function U(){for(const e of[...w.value])!K.value.some(s=>s.taskId===e)&&!_.value[e]&&W(e)}function $t(e){qe.value=e||[]}async function Ze(){const e=te.value.trim();if(!e){r.warning("请输入店铺名称");return}me.value=!0;try{await ms(e),te.value="",await $e(),r.success("已加入备选")}catch(t){r.error(t instanceof Error?t.message:"保存失败")}finally{me.value=!1}}async function Dt(e){try{await hs(e.id),await $e(),I.value=[],ke(),r.success("已删除")}catch(t){r.error(t instanceof Error?t.message:"删除失败")}}function Lt(){const e=new Set,t=te.value.trim();t&&e.add(t);for(const s of qe.value)s?.shopName?.trim()&&e.add(s.shopName.trim());if(S.value)for(const s of R.value){const o=(s||"").trim();if(!o)continue;const u=(o.split(/[/\\]/).filter(Boolean).pop()||"").replace(/\.[^.]+$/,"").trim();u&&e.add(u)}return[...e]}async function Ft(){const e=Lt();if(!e.length){r.warning("请勾选备选店铺,或在输入框中填写店名");return}if(S.value&&!R.value.length){r.warning("请先选择 ASIN 文件");return}he.value=!0;try{const t=await ys(e,{asinFiles:S.value?xe():[],countryCodes:ge()}),s=t.items||[];Ce.value=t.asinRowsByCountry||{};const o=new Map(I.value.map(l=>[(l.shopName||"").trim(),l]));for(const l of s)o.set((l.shopName||"").trim(),l);I.value=[...o.values()],ke(),je.value&&Kt(),r.success(`匹配 ${s.length} 个店铺`)}catch(t){r.error(t instanceof Error?t.message:"匹配失败")}finally{he.value=!1}}function Ut(e){const t=(e||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[t]||t||"—"}function Bt(e){const t=(e.matchMessage||"").trim();return t||(e.matched&&e.matchStatus==="MATCHED"?"紫鸟索引已命中,可推送队列":e.matched?"已关联索引,请结合状态列查看是否可推送":"未命中或未就绪,请检查店铺名与索引刷新")}function De(e){return`${(e.shopName||"").trim()}${e.shopId??""}`}function et(e){const t=e instanceof Error?e.message:String(e||"");return/记录不存在|不存在|已删除|not\s*found|404/i.test(t)}function Ot(){const e=A.value&&!S.value;return{enabled:e,mode:e?"DELETE_WHEN_PRICE_BELOW_MINIMUM":"NONE",deleteWhenPriceBelowMinimum:e,compareField:"price",thresholdField:"minimumPrice",target:"skip_asin",source:"frontend-price-track"}}function V(e){if(!e.length)return;const t=new Set(e.map(o=>De(o))),s=new Set(e.map(o=>(o.shopName||"").trim()).filter(o=>!!o));I.value=I.value.filter(o=>{const l=De(o),u=(o.shopName||"").trim();return!t.has(l)&&(!u||!s.has(u))}),ke()}function qt(e){K.value=K.value.filter(t=>!(e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId))}async function jt(e){const t=[...I.value];V([e]);const s=(e.shopName||"").trim();if(!s){r.success("已从匹配结果中移除");return}try{(await ks(s))?.removed&&(await F(),await $(),U()),r.success("已从匹配结果中移除")}catch(o){if(et(o)){await F(),await $(),U(),r.success("后端记录已不存在,已同步移除本地记录");return}I.value=t,ke(),r.error(o instanceof Error?o.message:"同步后端失败")}}function tt(e,t){const s=e.items?.[0],o=(t.shopName||"").trim(),l=t.skipAsins||e.skipAsinsByCountry||{},u=e.skipAsinDetailsByCountry||{},a=e.minimumPriceByCountryAndAsin||{},d=Ot(),T=s?.resultId??null,O=s?.loopRunId??null,ee=s?.roundIndex??null,h=s?.taskStatus||"RUNNING",D=s?.success??!1,E=s?.error||null,P=s?.outputFilename||null,H=s?.downloadUrl||null;return{type:"price-track-run",ts:Date.now(),data:{task_id:e.taskId,result_id:T,shop_name:o,shop_id:t.shopId??null,platform:t.platform||"",company_name:t.companyName||"",shop_mall_name:t.shopMallName||"",matched:!!t.matched,match_status:t.matchStatus||"",match_message:t.matchMessage||null,success:D,error:E,output_filename:P,download_url:H,task_status:h,loop_run_id:O,round_index:ee,country_codes:ge(),mode:A.value?"status":"asin",skip_asins:l,skip_asins_by_country:l,skip_asin_details_by_country:u,minimum_price_by_country_and_asin:a,skip_asin_delete_policy:d,delete_skip_asin_when_price_below_minimum:d.deleteWhenPriceBelowMinimum,deleteSkipAsinWhenPriceBelowMinimum:d.deleteWhenPriceBelowMinimum,asin_rows_by_country:Object.keys(Ce.value).length?Ce.value:e.asinRowsByCountry||{},taskId:e.taskId,resultId:T,shopName:o,shopId:t.shopId??null,platformName:t.platform||"",companyName:t.companyName||"",shopMallName:t.shopMallName||"",matchStatus:t.matchStatus||"",matchMessage:t.matchMessage||null,outputFilename:P,downloadUrl:H,taskStatus:h,loopRunId:O,roundIndex:ee}}}async function st(e){let t=0;const s=30;for(;;){if(b)return"STOPPED";try{const o=await pt([e]);if(t>0&&(p.value=`任务 ${e} 后端已恢复,继续等待执行结果...`),t=0,(o.missingTaskIds||[]).includes(e))return W(e),await F(),await $(),U(),"FAILED";const l=(o.items||[]).find(a=>a.task?.id===e),u=l?.task?.status||"";if(l){const a=_.value[e];_.value={..._.value,[e]:a?{...a,task:{...a.task||{},...l.task||{}}}:l},ie()}if(u&&(N.value={...N.value,[e]:u},ue()),u==="SUCCESS"||u==="FAILED")return W(e),await F(),await $(),U(),u}catch(o){const l=(o instanceof Error?o.message:String(o||"")).toLowerCase();if(!["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(a=>l.includes(a.toLowerCase())))throw o;if(t+=1,t>=s)throw new Error(`任务 ${e} 等待后端恢复超时,请稍后手动刷新查看状态`);p.value=`任务 ${e} 运行中,正在等待后端服务恢复(${t}/${s})...`,(t===1||t%5===0)&&r.warning(`任务 ${e} 运行中,后端服务暂时不可用,正在自动重试`),await X(B());continue}await X(B())}}function Jt(){return I.value.find(e=>e.matched)}async function Kt(){if(b||Se.value)return;if(!Ne.value){r.warning("请至少选择一个跟价模式");return}if(S.value&&!R.value.length){r.warning("请先选择 ASIN 文件");return}const e=pe();if(!e?.enqueue_json){r.error("当前环境未启用 pywebview enqueue_json");return}if(!I.value.filter(l=>l.matched).length){r.warning("无可用匹配店铺");return}Se.value=!0,j.value=!0,G.value="";let s=0,o=0;try{let l=0;for(;!b&&je.value;){const u=Jt();if(!u)break;l+=1;try{let a=0;const d=await(async()=>{for(;;){if(b)throw new Error("component disposed");try{return await ft({userId:0,statusMode:A.value,asinMode:S.value,items:[u],asinFiles:xe(),countryCodes:ge()})}catch(h){const D=(h instanceof Error?h.message:String(h||"")).toLowerCase(),E=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(P=>D.includes(P.toLowerCase()));if(a+=1,!E||a>=10)throw h;p.value="后端服务暂时不可用,正在重试创建任务("+a+"/10)...",await X(B())}}})();_.value={..._.value,[d.taskId]:{task:{id:d.taskId,status:"RUNNING"},items:d.items}},N.value={...N.value,[d.taskId]:"RUNNING"},ie(),ue();const T=tt(d,u);G.value=JSON.stringify(T,null,2);const O=await e.enqueue_json(T);if(!O?.success){o+=1,p.value="任务 "+d.taskId+" 推送失败,已自动继续下一条:"+(O?.error||"未知错误"),r.error(p.value),V([u]);continue}if(we(d.taskId),Z(!0),V([u]),p.value="任务 "+d.taskId+" 已入队,等待执行完成",await st(d.taskId)!=="SUCCESS"){o+=1,p.value="任务 "+d.taskId+" 执行失败,已自动继续下一条",r.error(p.value);continue}s+=1,p.value="任务 "+d.taskId+" 已完成"}catch(a){if(b)break;o+=1,p.value="第 "+l+" 条任务处理失败,已自动继续下一条:"+(a instanceof Error?a.message:"未知错误"),r.error(p.value),V([u]);continue}}(s>0||o>0)&&r.success("店铺任务推送已完成:成功 "+s+" 条,失败 "+o+" 条")}catch(l){if(b)return;p.value=l instanceof Error?l.message:"推送异常",r.error(p.value)}finally{Se.value=!1,j.value=!1}}function ce(e){k.value=e,m.value=e?.id??null,Y()}function de(){if(!k.value)return;const e=k.value.status||"";(e==="SUCCESS"||e==="FAILED"||e==="STOPPED")&&(k.value=null,m.value=null,Y())}async function Le(){if(!m.value)return null;try{const e=await gs(m.value);return ce(e),de(),k.value}catch(e){const t=(e instanceof Error?e.message:String(e||"")).toLowerCase();return["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(o=>t.includes(o.toLowerCase()))?k.value:(k.value=null,m.value=null,Y(),null)}}function Vt(e){_.value={..._.value,[e.taskId]:{task:{id:e.taskId,status:"RUNNING"},items:e.items}},N.value={...N.value,[e.taskId]:"RUNNING"},ie(),ue()}async function Wt(){if(!(!m.value||se.value)){se.value=!0;try{const e=await ws(m.value);ce(e),de(),r.success(e.status==="STOPPED"?"循环已停止":"已请求停止,当前子任务完成后将收尾")}catch(e){r.error(e instanceof Error?e.message:"停止循环失败")}finally{se.value=!1}}}async function Fe(e){if(b||Te.value||(e&&m.value!==e&&(m.value=e,Y()),!m.value))return;const t=pe();if(!t?.enqueue_json)throw new Error("当前环境未启用 pywebview enqueue_json");Te.value=!0;try{for(;!b&&m.value;){const s=await Le();if(!s||s.status==="SUCCESS"||s.status==="FAILED"||s.status==="STOPPED")break;if(s.activeTaskId){const h=s.activeTaskId;we(h),Z(!0);const D=await st(h);let E=0;const P=await(async()=>{for(;;){if(b)throw new Error("component disposed");try{return await _s(s.id,h)}catch(H){const Xt=(H instanceof Error?H.message:String(H||"")).toLowerCase(),Yt=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(Zt=>Xt.includes(Zt.toLowerCase()));if(E+=1,!Yt||E>=10)throw H;p.value=`循环任务 ${s.id} 等待后端恢复后确认子任务完成(${E}/10)...`,await X(B())}}})();if(ce(P),await F(),await $(),U(),de(),D!=="SUCCESS")throw new Error(P.errorMessage||`任务 ${s.activeTaskId} 执行失败`);continue}let o=0;const l=await(async()=>{for(;;){if(b)throw new Error("component disposed");try{return await bs(s.id)}catch(h){const D=(h instanceof Error?h.message:String(h||"")).toLowerCase(),E=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(P=>D.includes(P.toLowerCase()));if(o+=1,!E||o>=10)throw h;p.value=`循环任务 ${s.id} 等待后端恢复后继续派发(${o}/10)...`,await X(B())}}})();if(ce(l.loopRun||s),!l.childTaskRequest){de();break}const u=l.childTaskRequest,a=u.items?.[0];if(!a)throw new Error("循环任务缺少待执行店铺");let d=0;const T=await(async()=>{for(;;){if(b)throw new Error("component disposed");try{return await ft(u)}catch(h){const D=(h instanceof Error?h.message:String(h||"")).toLowerCase(),E=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(P=>D.includes(P.toLowerCase()));if(d+=1,!E||d>=10)throw h;p.value=`循环任务 ${s.id} 等待后端恢复后重试创建子任务(${d}/10)...`,await X(B())}}})();Vt(T);const O=tt(T,a);G.value=JSON.stringify(O,null,2);const ee=await t.enqueue_json(O);if(!ee?.success)throw new Error(ee?.error||`任务 ${T.taskId} 推送失败`);we(T.taskId),Z(!0),V([a]),p.value=`循环任务 ${s.id} 第 ${l.childTaskRequest.roundIndex||1} 轮已推送:${a.shopName||T.taskId}`}}finally{Te.value=!1}}async function Ht(){if(Ee.value){try{await Fe(m.value||void 0)}catch(t){t instanceof Error&&/子任务不存在|循环任务不存在|404/.test(t.message)&&(k.value=null,m.value=null,Y());const s=t instanceof Error?t.message:"循环执行失败";p.value=s,r.error(s)}return}if(!Ne.value){r.warning("请至少选择一个跟价模式");return}if(S.value&&!R.value.length){r.warning("请先选择 ASIN 文件");return}const e=I.value.filter(t=>t.matched);if(!e.length){r.warning("请先匹配可用店铺");return}j.value=!0,G.value="";try{const t=await Is({userId:0,statusMode:A.value,asinMode:S.value,items:e,asinFiles:xe(),countryCodes:ge(),executionMode:J.value,targetRounds:J.value==="FINITE"?Math.max(1,Number(ye.value)||1):void 0});ce(t),p.value=`循环任务 ${t.id} 已创建`,await Fe(t.id),de(),m.value||r.success("跟价循环已启动")}catch(t){const s=t instanceof Error?t.message:"启动循环失败";p.value=s,r.error(s)}finally{j.value=!1}}function B(){return Ss()}async function zt(){const e=w.value.filter(t=>t>0);if(e.length)try{const t=await pt(e);let s=!1;const o={..._.value};for(const l of t.missingTaskIds||[])W(l),delete o[l];for(const l of t.items||[]){const u=l.task?.id,a=l.task?.status;if(typeof u!="number"||u<=0)continue;const d=o[u];o[u]=d?{...d,task:{...d.task||{},...l.task||{}}}:l,a&&(N.value[u]=a,(a==="SUCCESS"||a==="FAILED")&&(W(u),s=!0))}_.value=o,ie(),ue(),await F(),U(),s&&await $()}catch{}}function Z(e=!1){if(b)return;if(M.value){if(!e)return;x.clearTimer("task-poll",M.value),M.value=null}const t=async()=>{if(M.value=null,!b){if(Ae.value){Z();return}if(w.value.length){Ae.value=!0;try{await zt()}finally{Ae.value=!1}!b&&w.value.length>0&&(M.value=x.setTimeout("task-poll",t,B()))}}};e?t():M.value=x.setTimeout("task-poll",t,B())}function Gt(){M.value&&(x.clearTimer("task-poll",M.value),M.value=null)}function we(e){w.value.includes(e)||(w.value=[...w.value,e],Ge())}function W(e){if(w.value=w.value.filter(t=>t!==e),Ge(),delete N.value[e],ue(),_.value[e]){const t={..._.value};delete t[e],_.value=t,ie()}}const Ue=q(()=>{const e=K.value.filter(s=>s.taskId&&w.value.includes(s.taskId)&&!nt(s.taskId)),t=new Set(e.map(s=>s.taskId).filter(s=>typeof s=="number"));for(const s of w.value){if(t.has(s))continue;const o=_.value[s]?.items?.[0];o&&e.push(o)}return e}),Be=q(()=>K.value.filter(e=>!e.taskId||!w.value.includes(e.taskId)||nt(e.taskId))),Qt=q(()=>Ue.value.length>0||Be.value.length>0);function at(e){return e&&(N.value[e]||_.value[e]?.task?.status)||""}function nt(e){const t=at(e);return t==="SUCCESS"||t==="FAILED"}function Oe(e){const t=e.taskId;return t?at(t)||e.taskStatus||"":e.taskStatus||""}function ot(e){const t=Oe(e);return t==="SUCCESS"?"已完成":t==="FAILED"?"失败":t==="RUNNING"?"执行中":e.success?"已完成":"等待中"}function lt(e){const t=Oe(e);return t==="SUCCESS"||e.success?"success":t==="FAILED"?"failed":"running"}function rt(e){return!e.resultId||!e.fileReady&&!e.downloadUrl?!1:Oe(e)==="SUCCESS"||e.success===!0}async function ut(e){if(!e.resultId)return;const t=e.outputFilename||`${e.shopName||"result"}.xlsx`,s=Cs(e.resultId),o=await Ts(s,t,`price-track:${e.resultId}`);o.success?r.success(`已保存:${o.path||t}`):o.error&&o.error!=="用户取消"&&r.error(o.error)}async function it(e){try{e.resultId!=null?await Ns(e.resultId):e.taskId!=null&&await Es(e.taskId),k.value&&(e.loopRunId!=null&&e.loopRunId===k.value.id||e.taskId!=null&&e.taskId===k.value.activeTaskId)&&await Le(),e.taskId!=null&&W(e.taskId),V([e]),await F(),await $(),U(),r.success("已删除")}catch(t){if(et(t)){e.taskId!=null&&W(e.taskId),V([e]),qt(e),await $(),U(),r.success("后端记录已不存在,已同步移除本地记录");return}r.error(t instanceof Error?t.message:"删除失败")}}return ts(()=>{!A.value&&!S.value&&Me("status"),kt(),gt(),wt(),_t(),bt(),$e().catch(()=>{}),Mt().catch(()=>{}),F().catch(()=>{}),$().catch(()=>{}),w.value.length&&Z(!0),m.value&&Le().then(e=>{e?.activeTaskId&&(we(e.activeTaskId),Z(!0)),e&&e.status!=="SUCCESS"&&e.status!=="FAILED"&&e.status!=="STOPPED"&&Fe(e.id)}).catch(()=>{m.value=null,Y()})}),ss(()=>{b=!0,Gt(),yt(),x.clearScope(),Q&&x.clearTimer("preference-save",Q)}),(e,t)=>{const s=ns,o=ls,l=rs,u=us;return i(),c("div",$s,[C(as,{active:"pricing"}),n("div",Ds,[n("aside",Ls,[t[27]||(t[27]=n("div",{class:"section-title"},"跟价模式",-1)),n("div",Fs,[n("label",Us,[n("input",{type:"radio",name:"price-track-mode",class:"mode-check-input",checked:A.value,onChange:t[0]||(t[0]=a=>Me("status"))},null,40,Bs),t[7]||(t[7]=n("span",{class:"mode-check-text"},"按商品状态(全量)",-1)),t[8]||(t[8]=n("span",{class:"mode-hint-inline"},"— 获取店铺所有在售ASIN跑跟价",-1))]),n("label",Os,[n("input",{type:"radio",name:"price-track-mode",class:"mode-check-input",checked:S.value,onChange:t[1]||(t[1]=a=>Me("asin"))},null,40,qs),t[9]||(t[9]=n("span",{class:"mode-check-text"},"按指定ASIN文档(自定义)",-1)),t[10]||(t[10]=n("span",{class:"mode-hint-inline"},"— 上传ASIN表格,按文档内ASIN跑跟价",-1))])]),t[28]||(t[28]=n("div",{class:"section-title"},"执行配置",-1)),n("div",js,[n("label",Js,[ct(n("input",{"onUpdate:modelValue":t[2]||(t[2]=a=>J.value=a),type:"radio",class:"mode-check-input",value:"FINITE"},null,512),[[dt,J.value]]),t[11]||(t[11]=n("span",{class:"mode-check-text"},"执行固定轮次",-1)),t[12]||(t[12]=n("span",{class:"mode-hint-inline"},"按整批店铺重复执行指定次数",-1))]),n("label",Ks,[ct(n("input",{"onUpdate:modelValue":t[3]||(t[3]=a=>J.value=a),type:"radio",class:"mode-check-input",value:"INFINITE"},null,512),[[dt,J.value]]),t[13]||(t[13]=n("span",{class:"mode-check-text"},"无限执行",-1)),t[14]||(t[14]=n("span",{class:"mode-hint-inline"},"上一轮全部成功后立即开始下一轮",-1))]),J.value==="FINITE"?(i(),c("div",Vs,[t[15]||(t[15]=n("span",{class:"hint"},"轮次",-1)),C(s,{modelValue:ye.value,"onUpdate:modelValue":t[4]||(t[4]=a=>ye.value=a),min:1,max:9999,disabled:Ee.value||j.value},null,8,["modelValue","disabled"])])):y("",!0)]),S.value?(i(),c(L,{key:0},[t[17]||(t[17]=n("div",{class:"section-title"},[ve("ASIN文档 "),n("span",{class:"tag-badge"},"自定义模式")],-1)),n("div",Ws,[t[16]||(t[16]=n("div",{class:"hint"},"上传包含ASIN的表格文件,按文档内的ASIN进行跟价。",-1)),n("div",{class:"btns"},[n("button",{type:"button",class:"opt-btn",onClick:It},"选择ASIN文件"),n("button",{type:"button",class:"opt-btn",onClick:St},"选择文件夹")]),n("div",Hs,[R.value.length?(i(!0),c(L,{key:0},fe(R.value,(a,d)=>(i(),c("span",{key:d},v(a),1))),128)):(i(),c("span",zs,"暂未选择"))])])],64)):y("",!0),A.value?(i(),c(L,{key:1},[t[19]||(t[19]=n("div",{class:"section-title"},"店铺名称",-1)),n("div",Gs,[t[18]||(t[18]=n("div",{class:"hint"},"输入店铺名后点「确认」加入下方备选区。可同时配合上方模式使用。",-1)),n("div",Qs,[C(o,{modelValue:te.value,"onUpdate:modelValue":t[5]||(t[5]=a=>te.value=a),clearable:"",placeholder:"请输入店铺名称",onKeyup:os(Ze,["enter"])},null,8,["modelValue"]),n("button",{type:"button",class:"opt-btn",disabled:me.value,onClick:Ze},v(me.value?"保存中…":"确认"),9,Xs)])]),t[20]||(t[20]=n("div",{class:"section-title"},"备选店铺",-1)),Ie.value.length?(i(),c("div",Zs,[C(u,{data:Ie.value,"row-key":"id",height:"160",class:"candidate-table",onSelectionChange:$t},{default:z(()=>[C(l,{type:"selection",width:"42"}),C(l,{prop:"shopName",label:"店铺名","min-width":"120","show-overflow-tooltip":""}),C(l,{label:"操作",width:"72",align:"center"},{default:z(({row:a})=>[n("button",{type:"button",class:"link-danger",onClick:d=>Dt(a)},"删除",8,ea)]),_:1})]),_:1},8,["data"])])):(i(),c("div",Ys,"暂无备选店铺,请先输入并确认"))],64)):y("",!0),S.value?y("",!0):(i(),c(L,{key:2},[t[23]||(t[23]=n("div",{class:"section-title"},"处理国家与顺序",-1)),t[24]||(t[24]=n("p",{class:"hint country-pref-hint"}," 勾选需要处理的站点;拖拽调整顺序。设置会按当前登录用户保存。 ",-1)),n("div",ta,[(i(!0),c(L,null,fe(Ct.value,a=>(i(),c("label",{key:a.code,class:"country-check-row"},[n("input",{type:"checkbox",class:"country-check-input",checked:Tt(a.code),disabled:Xe(a.code),onChange:d=>Nt(a.code,d)},null,40,sa),n("span",aa,v(a.label)+"("+v(a.code)+")",1)]))),128))]),g.value.length?(i(),c("div",na,[t[22]||(t[22]=n("div",{class:"country-order-caption"},"已选顺序(拖拽 ⋮⋮ 调整)",-1)),n("div",oa,[(i(!0),c(L,null,fe(g.value,(a,d)=>(i(),c("div",{key:a,class:_e(["country-drag-row",{dragging:ne.value===d}]),draggable:"true",onDragstart:T=>Pt(d),onDragend:At,onDragover:t[6]||(t[6]=vt(()=>{},["prevent"])),onDrop:vt(T=>Rt(d),["prevent"])},[t[21]||(t[21]=n("span",{class:"drag-handle",title:"拖动排序"},"⋮⋮",-1)),n("span",ra,v(Qe(a))+"("+v(a)+")",1)],42,la))),128))])])):y("",!0),Pe.value?(i(),c("div",ua,"保存中…")):y("",!0)],64)),A.value?(i(),c("div",ia,[...t[25]||(t[25]=[n("span",{class:"mode-status-dot active"},null,-1),n("span",{class:"mode-status-text"},"商品状态模式:将在售(Active)ASIN纳入跟价,跳过ASIN由后台配置的店铺维度数据提供",-1)])])):y("",!0),n("div",ca,[n("button",{type:"button",class:"btn-run",disabled:he.value,onClick:Ft},v(he.value?"匹配中…":"匹配店铺"),9,da),n("button",{type:"button",class:"btn-run btn-queue",disabled:j.value||!Ne.value,onClick:Ht},v(j.value?"推送中…":"推送到 Python 队列"),9,va)]),t[29]||(t[29]=n("p",{class:"loading-msg"},[ve("上传ASIN文档和多选店铺"),n("strong",null,"可同时生效"),ve(",跟价结果合并输出。全量和自定义的区别仅在于ASIN来源不同。")],-1)),k.value?(i(),c("div",fa,[n("div",pa,"循环任务 ID:"+v(k.value.id),1),n("div",ma,"状态:"+v(k.value.status||"-"),1),n("div",ha,"进度:"+v(ht.value),1),n("div",ya,"当前店铺:"+v((k.value.currentShopIndex||0)+1)+"/"+v(k.value.totalShopCount||0),1),k.value.errorMessage?(i(),c("div",ka,v(k.value.errorMessage),1)):y("",!0),n("button",{type:"button",class:"opt-btn loop-stop-btn",disabled:!Ee.value||se.value,onClick:Wt},v(se.value?"停止中...":"停止循环"),9,ga)])):y("",!0),p.value?(i(),c("div",wa,[t[26]||(t[26]=n("div",{class:"section-title queue-debug-title"},"推送结果",-1)),n("div",_a,v(p.value),1),G.value?(i(),c("pre",ba,v(G.value),1)):y("",!0)])):y("",!0)]),n("section",Ia,[t[38]||(t[38]=n("div",{class:"panel-header"},"匹配与任务",-1)),n("div",Sa,[n("div",Ca,[n("div",Ta,[t[30]||(t[30]=n("span",{class:"summary-label"},"备选店铺数",-1)),n("strong",null,v(oe.value.candidateCount),1)]),n("div",Na,[t[31]||(t[31]=n("span",{class:"summary-label"},"已结束任务",-1)),n("strong",null,v(oe.value.processedTaskCount),1)]),n("div",Ea,[t[32]||(t[32]=n("span",{class:"summary-label"},"成功任务",-1)),n("strong",null,v(oe.value.successTaskCount),1)]),n("div",Pa,[t[33]||(t[33]=n("span",{class:"summary-label"},"失败任务",-1)),n("strong",null,v(oe.value.failedTaskCount),1)])]),t[37]||(t[37]=n("div",{class:"subsection-title"},"匹配结果",-1)),I.value.length?(i(),is(u,{key:1,data:I.value,"row-key":De,"highlight-current-row":!1,class:"result-table match-table"},{default:z(()=>[C(l,{prop:"shopName",label:"店铺名","min-width":"100"}),C(l,{label:"匹配",width:"72",align:"center"},{default:z(({row:a})=>[n("span",{class:_e(a.matched?"ok":"fail")},v(a.matched?"是":"否"),3)]),_:1}),C(l,{prop:"shopId",label:"店铺ID","min-width":"120","show-overflow-tooltip":""}),C(l,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),C(l,{prop:"companyName",label:"公司","min-width":"100","show-overflow-tooltip":""}),C(l,{label:"状态",width:"100","show-overflow-tooltip":""},{default:z(({row:a})=>[ve(v(Ut(a.matchStatus)),1)]),_:1}),C(l,{label:"说明","min-width":"140","show-overflow-tooltip":""},{default:z(({row:a})=>[ve(v(Bt(a)),1)]),_:1}),C(l,{label:"操作",width:"72",align:"center"},{default:z(({row:a})=>[n("button",{type:"button",class:"link-danger",onClick:d=>jt(a)},"删除",8,Ra)]),_:1})]),_:1},8,["data"])):(i(),c("div",Aa,"完成「匹配店铺」后,在此展示紫鸟索引匹配结果,供核对后再推送队列。")),n("div",xa,[t[36]||(t[36]=n("div",{class:"result-list-header"},[n("span",null,"处理记录")],-1)),Qt.value?(i(),c(L,{key:1},[Ue.value.length?(i(),c("div",$a,[t[34]||(t[34]=n("div",{class:"result-subsection-title"},"当前任务",-1)),n("ul",Da,[(i(!0),c(L,null,fe(Ue.value,a=>(i(),c("li",{key:`cur-${a.resultId}-${a.taskId}`,class:"task-item split-result-item"},[n("div",La,[a.roundIndex?(i(),c("div",Fa,"轮次:第 "+v(a.roundIndex)+" 轮",1)):y("",!0),n("span",{class:"id",title:a.shopName||""},v(a.shopName||"-"),9,Ua),n("div",Ba,"任务 ID:"+v(a.taskId??"-"),1),a.platform?(i(),c("div",Oa,"平台:"+v(a.platform),1)):y("",!0),a.error?(i(),c("div",qa,"错误:"+v(a.error),1)):y("",!0)]),n("div",ja,[n("span",{class:_e(["status",lt(a)])},v(ot(a)),3),rt(a)?(i(),c("button",{key:0,type:"button",class:"download",onClick:d=>ut(a)}," 下载 ",8,Ja)):y("",!0),n("button",{type:"button",class:"btn-delete",onClick:d=>it(a)},"删除",8,Ka)])]))),128))])])):y("",!0),Be.value.length?(i(),c("div",Va,[t[35]||(t[35]=n("div",{class:"result-subsection-title"},"历史记录",-1)),n("ul",Wa,[(i(!0),c(L,null,fe(Be.value,a=>(i(),c("li",{key:`his-${a.resultId}-${a.taskId}`,class:"task-item split-result-item"},[n("div",Ha,[a.roundIndex?(i(),c("div",za,"轮次:第 "+v(a.roundIndex)+" 轮",1)):y("",!0),n("span",{class:"id",title:a.shopName||""},v(a.shopName||"-"),9,Ga),n("div",Qa,"任务 ID:"+v(a.taskId??"-"),1),a.outputFilename?(i(),c("div",Xa,"文件:"+v(a.outputFilename),1)):y("",!0),a.error?(i(),c("div",Ya,"错误:"+v(a.error),1)):y("",!0)]),n("div",Za,[n("span",{class:_e(["status",lt(a)])},v(ot(a)),3),rt(a)?(i(),c("button",{key:0,type:"button",class:"download",onClick:d=>ut(a)}," 下载 ",8,en)):y("",!0),n("button",{type:"button",class:"btn-delete",onClick:d=>it(a)},"删除",8,tn)])]))),128))])])):y("",!0)],64)):(i(),c("div",Ma,"暂无处理记录。推送队列并等待 Python 回传后,将在此显示下载链接。"))])])])])])}}}),an=Ps(sn,[["__scopeId","data-v-c91dd406"]]);As(an).use(Rs).mount("#app"); +import{d as es,o as ts,M as ss,a as i,c,b as C,B as as,e as n,w as ct,x as dt,aR as ns,f as y,F as L,y as ve,r as fe,t as v,ad as os,ae as ls,af as z,ag as rs,ah as us,ai as vt,n as _e,ak as is,g as f,h as q,i as pe,E as r,aS as cs,aT as ds,aU as vs,aV as fs,aW as ps,aX as ms,aY as hs,aZ as ys,a_ as ks,a$ as ft,b0 as gs,b1 as ws,b2 as _s,b3 as bs,b4 as Is,V as Ss,b5 as Cs,s as Ts,b6 as Ns,b7 as Es,b8 as pt,_ as Ps,q as As,u as Rs}from"./java-modules-B8c-YG5x.js";/* empty css */import{e as xs}from"./brand-COze15GJ.js";import{c as Ms}from"./categorized-timers-JPA-olTr.js";const $s={class:"page-shell module-page"},Ds={class:"main-content"},Ls={class:"left-panel"},Fs={class:"mode-zone"},Us={class:"mode-check-row"},Bs=["checked"],Os={class:"mode-check-row"},qs=["checked"],js={class:"mode-zone"},Js={class:"mode-check-row"},Ks={class:"mode-check-row"},Vs={key:0,class:"loop-round-input"},Ws={class:"upload-zone"},Hs={class:"selected-files clean-placeholder"},zs={key:1,class:"text-muted"},Gs={class:"input-zone"},Qs={class:"input-row"},Xs=["disabled"],Ys={key:0,class:"empty-candidates"},Zs={key:1,class:"candidate-table-scroll"},ea=["onClick"],ta={class:"country-pref-checks"},sa=["checked","disabled","onChange"],aa={class:"country-check-text"},na={key:0,class:"country-order-panel"},oa={class:"country-order-list"},la=["onDragstart","onDrop"],ra={class:"country-drag-label"},ua={key:1,class:"country-pref-status"},ia={key:3,class:"mode-status-bar"},ca={class:"run-row"},da=["disabled"],va=["disabled"],fa={key:4,class:"loop-status-card"},pa={class:"loop-status-line"},ma={class:"loop-status-line"},ha={class:"loop-status-line"},ya={class:"loop-status-line"},ka={key:0,class:"loop-status-line loop-error"},ga=["disabled"],wa={key:5,class:"queue-debug-card"},_a={class:"queue-debug-line"},ba={key:0,class:"queue-debug-payload"},Ia={class:"right-panel"},Sa={class:"task-list-wrap"},Ca={class:"clean-result-summary pr-summary"},Ta={class:"summary-card"},Na={class:"summary-card"},Ea={class:"summary-card"},Pa={class:"summary-card"},Aa={key:0,class:"empty-tasks narrow"},Ra=["onClick"],xa={class:"result-list-wrap"},Ma={key:0,class:"empty-tasks"},$a={key:0,class:"result-subsection"},Da={class:"task-list clean-result-list"},La={class:"left split-result-main"},Fa={key:0,class:"files"},Ua=["title"],Ba={class:"files"},Oa={key:1,class:"files"},qa={key:2,class:"files"},ja={class:"task-right split-result-actions"},Ja=["onClick"],Ka=["onClick"],Va={key:1,class:"result-subsection"},Wa={class:"task-list clean-result-list"},Ha={class:"left split-result-main"},za={key:0,class:"files"},Ga=["title"],Qa={class:"files"},Xa={key:1,class:"files"},Ya={key:2,class:"files"},Za={class:"task-right split-result-actions"},en=["onClick"],tn=["onClick"],sn=es({__name:"BrandPriceTrackTab",setup(nn){const be=[{code:"DE",label:"德国"},{code:"UK",label:"英国"},{code:"FR",label:"法国"},{code:"IT",label:"意大利"},{code:"ES",label:"西班牙"}],te=f(""),Ie=f([]),qe=f([]),I=f([]),me=f(!1),he=f(!1),j=f(!1),Se=f(!1),je=f(!1),p=f(""),G=f(""),Ce=f({}),J=f("FINITE"),ye=f(1),m=f(null),k=f(null),Te=f(!1),se=f(!1),A=f(!0),S=f(!1),R=f([]),ae=f([]),Ne=q(()=>A.value||S.value),mt=q(()=>{const e=k.value?.status||"";return e==="SUCCESS"||e==="FAILED"||e==="STOPPED"}),Ee=q(()=>!!m.value&&!mt.value),ht=q(()=>{const e=k.value;if(!e)return"";const t=e.currentRound||1;if(e.executionMode==="INFINITE")return`第 ${t} 轮(无限)`;const s=Math.max(1,e.targetRounds||ye.value||1);return`第 ${t}/${s} 轮`}),g=f(["DE","UK","FR","IT","ES"]),ne=f(null),Pe=f(!1),Je=f(!1);let Q=null;const oe=f({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),K=f([]),w=f([]),N=f({}),_=f({}),M=f(null),Ae=f(!1);let b=!1;const x=Ms("price-track");function X(e){return b?Promise.resolve():x.sleep("queue-wait",e)}function yt(){x.clearCategory("queue-wait")}function le(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function Ke(){return`price-track:tasks:${le()}`}function Ve(){return`price-track:task-status:${le()}`}function We(){return`price-track:tasks-batch-snapshot:${le()}`}function He(){return`price-track:matched-items:${le()}`}function ze(){return`price-track:active-loop:${le()}`}function re(e,t,s){if(!(typeof window>"u"))try{s?window.localStorage.removeItem(e):window.localStorage.setItem(e,JSON.stringify(t))}catch{}}function kt(){try{const e=typeof window<"u"?window.localStorage.getItem(Ke()):null;if(!e){w.value=[];return}const t=JSON.parse(e);w.value=Array.isArray(t)?t.filter(s=>typeof s=="number"&&s>0):[]}catch{w.value=[]}}function Ge(){re(Ke(),w.value,w.value.length===0)}function gt(){try{const e=typeof window<"u"?window.localStorage.getItem(Ve()):null;if(!e)return;const t=JSON.parse(e),s={};for(const[o,l]of Object.entries(t)){const u=Number(o);u>0&&typeof l=="string"&&(s[u]=l)}N.value=s}catch{}}function ue(){re(Ve(),N.value,Object.keys(N.value).length===0)}function wt(){try{const e=typeof window<"u"?window.localStorage.getItem(We()):null;if(!e)return;const t=JSON.parse(e),s={};for(const[o,l]of Object.entries(t)){const u=Number(o);u>0&&l&&typeof l=="object"&&(s[u]=l)}_.value=s}catch{}}function ie(){re(We(),_.value,Object.keys(_.value).length===0)}function _t(){try{const e=typeof window<"u"?window.localStorage.getItem(He()):null;if(!e)return;const t=JSON.parse(e);Array.isArray(t)&&(I.value=t)}catch{}}function ke(){re(He(),I.value,I.value.length===0)}function bt(){try{const e=typeof window<"u"?window.localStorage.getItem(ze()):null;if(!e){m.value=null;return}const t=Number(JSON.parse(e));m.value=Number.isFinite(t)&&t>0?t:null}catch{m.value=null}}function Y(){re(ze(),m.value,!m.value)}async function It(){const e=pe();if(e?.select_files){const t=await e.select_files({filters:[{name:"Excel/CSV",extensions:"xlsx,xls,csv"}],multiple:!0});t?.paths?.length&&(R.value=t.paths,ae.value=await Re(t.paths),r.success(`已选择 ${t.paths.length} 个ASIN文件`));return}if(e?.select_brand_xlsx_files){const t=await e.select_brand_xlsx_files();if(!t?.length)return;R.value=t,ae.value=await Re(t),r.success(`已选择 ${t.length} 个ASIN文件`);return}r.warning("当前环境不支持文件选择,请在本地客户端中打开")}async function St(){const e=pe();if(!e?.select_brand_folder){r.warning("当前环境不支持文件夹选择,请在本地客户端中打开");return}try{const t=await e.select_brand_folder();if(!t)return;const s=await xs(t);if(!s.success||!s.items?.length){r.warning(s.error||"该文件夹下没有可用的 xlsx 文件");return}R.value=s.items.map(o=>o.relativePath||o.absolutePath),ae.value=await Re(s.items),r.success(`已选择文件夹内 ${s.items.length} 个ASIN文件`)}catch(t){r.error(t instanceof Error?t.message:"选择失败")}}async function Re(e){const t=pe();if(!t?.upload_file_to_java)return[];const s=[];for(const o of e){const l=typeof o=="string"?o:o.absolutePath,u=typeof o=="string"?void 0:o.relativePath,a=await t.upload_file_to_java(l,u);if(!a?.success||!a.data)throw new Error(a?.error||a?.message||`上传失败:${l}`);s.push(a.data)}return s}function xe(){return ae.value.length?ae.value.map(e=>e.localPath).filter(e=>!!e):R.value}function ge(){return S.value?be.map(e=>e.code):[...g.value]}function Me(e){A.value=e==="status",S.value=e==="asin"}function Qe(e){return be.find(s=>s.code===e)?.label??e}const Ct=q(()=>{const e=g.value,t=new Set(e),s=e.map(l=>({code:l,label:Qe(l)})),o=be.filter(l=>!t.has(l.code)).map(l=>({code:l.code,label:l.label}));return[...s,...o]});function Tt(e){return g.value.includes(e)}function Xe(e){return g.value.length===1&&g.value[0]===e}function Nt(e,t){const s=t.target;if(s){if(!s.checked&&Xe(e)){s.checked=!0,r.warning("至少保留 1 个国家");return}Et(e,s.checked)}}function Et(e,t){if(Je.value=!0,t)g.value.includes(e)||(g.value=[...g.value,e]);else{if(g.value.length<=1){r.warning("至少保留 1 个国家");return}g.value=g.value.filter(s=>s!==e)}Ye()}function Pt(e){ne.value=e}function At(){ne.value=null}function Rt(e){const t=ne.value;if(ne.value=null,t==null||t===e)return;Je.value=!0;const s=[...g.value],[o]=s.splice(t,1);s.splice(e,0,o),g.value=s,Ye()}function Ye(){Q&&x.clearTimer("preference-save",Q),Q=x.setTimeout("preference-save",()=>{Q=null,xt()},450)}async function xt(){if(!(g.value.length<1)){Pe.value=!0;try{await cs(g.value)}catch(e){r.error(e instanceof Error?e.message:"保存国家顺序失败")}finally{Pe.value=!1}}}async function Mt(){try{const e=await ds();e?.countryCodes?.length&&(g.value=[...e.countryCodes])}catch{}}async function $e(){try{Ie.value=await vs()}catch(e){r.error(e instanceof Error?e.message:"加载备选失败")}}async function $(){try{oe.value=await fs()}catch{}}async function F(){try{const e=await ps();K.value=e.items||[]}catch{K.value=[]}}function U(){for(const e of[...w.value])!K.value.some(s=>s.taskId===e)&&!_.value[e]&&W(e)}function $t(e){qe.value=e||[]}async function Ze(){const e=te.value.trim();if(!e){r.warning("请输入店铺名称");return}me.value=!0;try{await ms(e),te.value="",await $e(),r.success("已加入备选")}catch(t){r.error(t instanceof Error?t.message:"保存失败")}finally{me.value=!1}}async function Dt(e){try{await hs(e.id),await $e(),I.value=[],ke(),r.success("已删除")}catch(t){r.error(t instanceof Error?t.message:"删除失败")}}function Lt(){const e=new Set,t=te.value.trim();t&&e.add(t);for(const s of qe.value)s?.shopName?.trim()&&e.add(s.shopName.trim());if(S.value)for(const s of R.value){const o=(s||"").trim();if(!o)continue;const u=(o.split(/[/\\]/).filter(Boolean).pop()||"").replace(/\.[^.]+$/,"").trim();u&&e.add(u)}return[...e]}async function Ft(){const e=Lt();if(!e.length){r.warning("请勾选备选店铺,或在输入框中填写店名");return}if(S.value&&!R.value.length){r.warning("请先选择 ASIN 文件");return}he.value=!0;try{const t=await ys(e,{asinFiles:S.value?xe():[],countryCodes:ge()}),s=t.items||[];Ce.value=t.asinRowsByCountry||{};const o=new Map(I.value.map(l=>[(l.shopName||"").trim(),l]));for(const l of s)o.set((l.shopName||"").trim(),l);I.value=[...o.values()],ke(),je.value&&Kt(),r.success(`匹配 ${s.length} 个店铺`)}catch(t){r.error(t instanceof Error?t.message:"匹配失败")}finally{he.value=!1}}function Ut(e){const t=(e||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[t]||t||"—"}function Bt(e){const t=(e.matchMessage||"").trim();return t||(e.matched&&e.matchStatus==="MATCHED"?"紫鸟索引已命中,可推送队列":e.matched?"已关联索引,请结合状态列查看是否可推送":"未命中或未就绪,请检查店铺名与索引刷新")}function De(e){return`${(e.shopName||"").trim()}${e.shopId??""}`}function et(e){const t=e instanceof Error?e.message:String(e||"");return/记录不存在|不存在|已删除|not\s*found|404/i.test(t)}function Ot(){const e=A.value&&!S.value;return{enabled:e,mode:e?"DELETE_WHEN_PRICE_BELOW_MINIMUM":"NONE",deleteWhenPriceBelowMinimum:e,compareField:"price",thresholdField:"minimumPrice",target:"skip_asin",source:"frontend-price-track"}}function V(e){if(!e.length)return;const t=new Set(e.map(o=>De(o))),s=new Set(e.map(o=>(o.shopName||"").trim()).filter(o=>!!o));I.value=I.value.filter(o=>{const l=De(o),u=(o.shopName||"").trim();return!t.has(l)&&(!u||!s.has(u))}),ke()}function qt(e){K.value=K.value.filter(t=>!(e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId))}async function jt(e){const t=[...I.value];V([e]);const s=(e.shopName||"").trim();if(!s){r.success("已从匹配结果中移除");return}try{(await ks(s))?.removed&&(await F(),await $(),U()),r.success("已从匹配结果中移除")}catch(o){if(et(o)){await F(),await $(),U(),r.success("后端记录已不存在,已同步移除本地记录");return}I.value=t,ke(),r.error(o instanceof Error?o.message:"同步后端失败")}}function tt(e,t){const s=e.items?.[0],o=(t.shopName||"").trim(),l=t.skipAsins||e.skipAsinsByCountry||{},u=e.skipAsinDetailsByCountry||{},a=e.minimumPriceByCountryAndAsin||{},d=Ot(),T=s?.resultId??null,O=s?.loopRunId??null,ee=s?.roundIndex??null,h=s?.taskStatus||"RUNNING",D=s?.success??!1,E=s?.error||null,P=s?.outputFilename||null,H=s?.downloadUrl||null;return{type:"price-track-run",ts:Date.now(),data:{task_id:e.taskId,result_id:T,shop_name:o,shop_id:t.shopId??null,platform:t.platform||"",company_name:t.companyName||"",shop_mall_name:t.shopMallName||"",matched:!!t.matched,match_status:t.matchStatus||"",match_message:t.matchMessage||null,success:D,error:E,output_filename:P,download_url:H,task_status:h,loop_run_id:O,round_index:ee,country_codes:ge(),mode:A.value?"status":"asin",skip_asins:l,skip_asins_by_country:l,skip_asin_details_by_country:u,minimum_price_by_country_and_asin:a,skip_asin_delete_policy:d,delete_skip_asin_when_price_below_minimum:d.deleteWhenPriceBelowMinimum,deleteSkipAsinWhenPriceBelowMinimum:d.deleteWhenPriceBelowMinimum,asin_rows_by_country:Object.keys(Ce.value).length?Ce.value:e.asinRowsByCountry||{},taskId:e.taskId,resultId:T,shopName:o,shopId:t.shopId??null,platformName:t.platform||"",companyName:t.companyName||"",shopMallName:t.shopMallName||"",matchStatus:t.matchStatus||"",matchMessage:t.matchMessage||null,outputFilename:P,downloadUrl:H,taskStatus:h,loopRunId:O,roundIndex:ee}}}async function st(e){let t=0;const s=30;for(;;){if(b)return"STOPPED";try{const o=await pt([e]);if(t>0&&(p.value=`任务 ${e} 后端已恢复,继续等待执行结果...`),t=0,(o.missingTaskIds||[]).includes(e))return W(e),await F(),await $(),U(),"FAILED";const l=(o.items||[]).find(a=>a.task?.id===e),u=l?.task?.status||"";if(l){const a=_.value[e];_.value={..._.value,[e]:a?{...a,task:{...a.task||{},...l.task||{}}}:l},ie()}if(u&&(N.value={...N.value,[e]:u},ue()),u==="SUCCESS"||u==="FAILED")return W(e),await F(),await $(),U(),u}catch(o){const l=(o instanceof Error?o.message:String(o||"")).toLowerCase();if(!["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(a=>l.includes(a.toLowerCase())))throw o;if(t+=1,t>=s)throw new Error(`任务 ${e} 等待后端恢复超时,请稍后手动刷新查看状态`);p.value=`任务 ${e} 运行中,正在等待后端服务恢复(${t}/${s})...`,(t===1||t%5===0)&&r.warning(`任务 ${e} 运行中,后端服务暂时不可用,正在自动重试`),await X(B());continue}await X(B())}}function Jt(){return I.value.find(e=>e.matched)}async function Kt(){if(b||Se.value)return;if(!Ne.value){r.warning("请至少选择一个跟价模式");return}if(S.value&&!R.value.length){r.warning("请先选择 ASIN 文件");return}const e=pe();if(!e?.enqueue_json){r.error("当前环境未启用 pywebview enqueue_json");return}if(!I.value.filter(l=>l.matched).length){r.warning("无可用匹配店铺");return}Se.value=!0,j.value=!0,G.value="";let s=0,o=0;try{let l=0;for(;!b&&je.value;){const u=Jt();if(!u)break;l+=1;try{let a=0;const d=await(async()=>{for(;;){if(b)throw new Error("component disposed");try{return await ft({userId:0,statusMode:A.value,asinMode:S.value,items:[u],asinFiles:xe(),countryCodes:ge()})}catch(h){const D=(h instanceof Error?h.message:String(h||"")).toLowerCase(),E=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(P=>D.includes(P.toLowerCase()));if(a+=1,!E||a>=10)throw h;p.value="后端服务暂时不可用,正在重试创建任务("+a+"/10)...",await X(B())}}})();_.value={..._.value,[d.taskId]:{task:{id:d.taskId,status:"RUNNING"},items:d.items}},N.value={...N.value,[d.taskId]:"RUNNING"},ie(),ue();const T=tt(d,u);G.value=JSON.stringify(T,null,2);const O=await e.enqueue_json(T);if(!O?.success){o+=1,p.value="任务 "+d.taskId+" 推送失败,已自动继续下一条:"+(O?.error||"未知错误"),r.error(p.value),V([u]);continue}if(we(d.taskId),Z(!0),V([u]),p.value="任务 "+d.taskId+" 已入队,等待执行完成",await st(d.taskId)!=="SUCCESS"){o+=1,p.value="任务 "+d.taskId+" 执行失败,已自动继续下一条",r.error(p.value);continue}s+=1,p.value="任务 "+d.taskId+" 已完成"}catch(a){if(b)break;o+=1,p.value="第 "+l+" 条任务处理失败,已自动继续下一条:"+(a instanceof Error?a.message:"未知错误"),r.error(p.value),V([u]);continue}}(s>0||o>0)&&r.success("店铺任务推送已完成:成功 "+s+" 条,失败 "+o+" 条")}catch(l){if(b)return;p.value=l instanceof Error?l.message:"推送异常",r.error(p.value)}finally{Se.value=!1,j.value=!1}}function ce(e){k.value=e,m.value=e?.id??null,Y()}function de(){if(!k.value)return;const e=k.value.status||"";(e==="SUCCESS"||e==="FAILED"||e==="STOPPED")&&(k.value=null,m.value=null,Y())}async function Le(){if(!m.value)return null;try{const e=await gs(m.value);return ce(e),de(),k.value}catch(e){const t=(e instanceof Error?e.message:String(e||"")).toLowerCase();return["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(o=>t.includes(o.toLowerCase()))?k.value:(k.value=null,m.value=null,Y(),null)}}function Vt(e){_.value={..._.value,[e.taskId]:{task:{id:e.taskId,status:"RUNNING"},items:e.items}},N.value={...N.value,[e.taskId]:"RUNNING"},ie(),ue()}async function Wt(){if(!(!m.value||se.value)){se.value=!0;try{const e=await ws(m.value);ce(e),de(),r.success(e.status==="STOPPED"?"循环已停止":"已请求停止,当前子任务完成后将收尾")}catch(e){r.error(e instanceof Error?e.message:"停止循环失败")}finally{se.value=!1}}}async function Fe(e){if(b||Te.value||(e&&m.value!==e&&(m.value=e,Y()),!m.value))return;const t=pe();if(!t?.enqueue_json)throw new Error("当前环境未启用 pywebview enqueue_json");Te.value=!0;try{for(;!b&&m.value;){const s=await Le();if(!s||s.status==="SUCCESS"||s.status==="FAILED"||s.status==="STOPPED")break;if(s.activeTaskId){const h=s.activeTaskId;we(h),Z(!0);const D=await st(h);let E=0;const P=await(async()=>{for(;;){if(b)throw new Error("component disposed");try{return await _s(s.id,h)}catch(H){const Xt=(H instanceof Error?H.message:String(H||"")).toLowerCase(),Yt=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(Zt=>Xt.includes(Zt.toLowerCase()));if(E+=1,!Yt||E>=10)throw H;p.value=`循环任务 ${s.id} 等待后端恢复后确认子任务完成(${E}/10)...`,await X(B())}}})();if(ce(P),await F(),await $(),U(),de(),D!=="SUCCESS")throw new Error(P.errorMessage||`任务 ${s.activeTaskId} 执行失败`);continue}let o=0;const l=await(async()=>{for(;;){if(b)throw new Error("component disposed");try{return await bs(s.id)}catch(h){const D=(h instanceof Error?h.message:String(h||"")).toLowerCase(),E=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(P=>D.includes(P.toLowerCase()));if(o+=1,!E||o>=10)throw h;p.value=`循环任务 ${s.id} 等待后端恢复后继续派发(${o}/10)...`,await X(B())}}})();if(ce(l.loopRun||s),!l.childTaskRequest){de();break}const u=l.childTaskRequest,a=u.items?.[0];if(!a)throw new Error("循环任务缺少待执行店铺");let d=0;const T=await(async()=>{for(;;){if(b)throw new Error("component disposed");try{return await ft(u)}catch(h){const D=(h instanceof Error?h.message:String(h||"")).toLowerCase(),E=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(P=>D.includes(P.toLowerCase()));if(d+=1,!E||d>=10)throw h;p.value=`循环任务 ${s.id} 等待后端恢复后重试创建子任务(${d}/10)...`,await X(B())}}})();Vt(T);const O=tt(T,a);G.value=JSON.stringify(O,null,2);const ee=await t.enqueue_json(O);if(!ee?.success)throw new Error(ee?.error||`任务 ${T.taskId} 推送失败`);we(T.taskId),Z(!0),V([a]),p.value=`循环任务 ${s.id} 第 ${l.childTaskRequest.roundIndex||1} 轮已推送:${a.shopName||T.taskId}`}}finally{Te.value=!1}}async function Ht(){if(Ee.value){try{await Fe(m.value||void 0)}catch(t){t instanceof Error&&/子任务不存在|循环任务不存在|404/.test(t.message)&&(k.value=null,m.value=null,Y());const s=t instanceof Error?t.message:"循环执行失败";p.value=s,r.error(s)}return}if(!Ne.value){r.warning("请至少选择一个跟价模式");return}if(S.value&&!R.value.length){r.warning("请先选择 ASIN 文件");return}const e=I.value.filter(t=>t.matched);if(!e.length){r.warning("请先匹配可用店铺");return}j.value=!0,G.value="";try{const t=await Is({userId:0,statusMode:A.value,asinMode:S.value,items:e,asinFiles:xe(),countryCodes:ge(),executionMode:J.value,targetRounds:J.value==="FINITE"?Math.max(1,Number(ye.value)||1):void 0});ce(t),p.value=`循环任务 ${t.id} 已创建`,await Fe(t.id),de(),m.value||r.success("跟价循环已启动")}catch(t){const s=t instanceof Error?t.message:"启动循环失败";p.value=s,r.error(s)}finally{j.value=!1}}function B(){return Ss()}async function zt(){const e=w.value.filter(t=>t>0);if(e.length)try{const t=await pt(e);let s=!1;const o={..._.value};for(const l of t.missingTaskIds||[])W(l),delete o[l];for(const l of t.items||[]){const u=l.task?.id,a=l.task?.status;if(typeof u!="number"||u<=0)continue;const d=o[u];o[u]=d?{...d,task:{...d.task||{},...l.task||{}}}:l,a&&(N.value[u]=a,(a==="SUCCESS"||a==="FAILED")&&(W(u),s=!0))}_.value=o,ie(),ue(),await F(),U(),s&&await $()}catch{}}function Z(e=!1){if(b)return;if(M.value){if(!e)return;x.clearTimer("task-poll",M.value),M.value=null}const t=async()=>{if(M.value=null,!b){if(Ae.value){Z();return}if(w.value.length){Ae.value=!0;try{await zt()}finally{Ae.value=!1}!b&&w.value.length>0&&(M.value=x.setTimeout("task-poll",t,B()))}}};e?t():M.value=x.setTimeout("task-poll",t,B())}function Gt(){M.value&&(x.clearTimer("task-poll",M.value),M.value=null)}function we(e){w.value.includes(e)||(w.value=[...w.value,e],Ge())}function W(e){if(w.value=w.value.filter(t=>t!==e),Ge(),delete N.value[e],ue(),_.value[e]){const t={..._.value};delete t[e],_.value=t,ie()}}const Ue=q(()=>{const e=K.value.filter(s=>s.taskId&&w.value.includes(s.taskId)&&!nt(s.taskId)),t=new Set(e.map(s=>s.taskId).filter(s=>typeof s=="number"));for(const s of w.value){if(t.has(s))continue;const o=_.value[s]?.items?.[0];o&&e.push(o)}return e}),Be=q(()=>K.value.filter(e=>!e.taskId||!w.value.includes(e.taskId)||nt(e.taskId))),Qt=q(()=>Ue.value.length>0||Be.value.length>0);function at(e){return e&&(N.value[e]||_.value[e]?.task?.status)||""}function nt(e){const t=at(e);return t==="SUCCESS"||t==="FAILED"}function Oe(e){const t=e.taskId;return t?at(t)||e.taskStatus||"":e.taskStatus||""}function ot(e){const t=Oe(e);return t==="SUCCESS"?"已完成":t==="FAILED"?"失败":t==="RUNNING"?"执行中":e.success?"已完成":"等待中"}function lt(e){const t=Oe(e);return t==="SUCCESS"||e.success?"success":t==="FAILED"?"failed":"running"}function rt(e){return!e.resultId||!e.fileReady&&!e.downloadUrl?!1:Oe(e)==="SUCCESS"||e.success===!0}async function ut(e){if(!e.resultId)return;const t=e.outputFilename||`${e.shopName||"result"}.xlsx`,s=Cs(e.resultId),o=await Ts(s,t,`price-track:${e.resultId}`);o.success?r.success(`已保存:${o.path||t}`):o.error&&o.error!=="用户取消"&&r.error(o.error)}async function it(e){try{e.resultId!=null?await Ns(e.resultId):e.taskId!=null&&await Es(e.taskId),k.value&&(e.loopRunId!=null&&e.loopRunId===k.value.id||e.taskId!=null&&e.taskId===k.value.activeTaskId)&&await Le(),e.taskId!=null&&W(e.taskId),V([e]),await F(),await $(),U(),r.success("已删除")}catch(t){if(et(t)){e.taskId!=null&&W(e.taskId),V([e]),qt(e),await $(),U(),r.success("后端记录已不存在,已同步移除本地记录");return}r.error(t instanceof Error?t.message:"删除失败")}}return ts(()=>{!A.value&&!S.value&&Me("status"),kt(),gt(),wt(),_t(),bt(),$e().catch(()=>{}),Mt().catch(()=>{}),F().catch(()=>{}),$().catch(()=>{}),w.value.length&&Z(!0),m.value&&Le().then(e=>{e?.activeTaskId&&(we(e.activeTaskId),Z(!0)),e&&e.status!=="SUCCESS"&&e.status!=="FAILED"&&e.status!=="STOPPED"&&Fe(e.id)}).catch(()=>{m.value=null,Y()})}),ss(()=>{b=!0,Gt(),yt(),x.clearScope(),Q&&x.clearTimer("preference-save",Q)}),(e,t)=>{const s=ns,o=ls,l=rs,u=us;return i(),c("div",$s,[C(as,{active:"pricing"}),n("div",Ds,[n("aside",Ls,[t[27]||(t[27]=n("div",{class:"section-title"},"跟价模式",-1)),n("div",Fs,[n("label",Us,[n("input",{type:"radio",name:"price-track-mode",class:"mode-check-input",checked:A.value,onChange:t[0]||(t[0]=a=>Me("status"))},null,40,Bs),t[7]||(t[7]=n("span",{class:"mode-check-text"},"按商品状态(全量)",-1)),t[8]||(t[8]=n("span",{class:"mode-hint-inline"},"— 获取店铺所有在售ASIN跑跟价",-1))]),n("label",Os,[n("input",{type:"radio",name:"price-track-mode",class:"mode-check-input",checked:S.value,onChange:t[1]||(t[1]=a=>Me("asin"))},null,40,qs),t[9]||(t[9]=n("span",{class:"mode-check-text"},"按指定ASIN文档(自定义)",-1)),t[10]||(t[10]=n("span",{class:"mode-hint-inline"},"— 上传ASIN表格,按文档内ASIN跑跟价",-1))])]),t[28]||(t[28]=n("div",{class:"section-title"},"执行配置",-1)),n("div",js,[n("label",Js,[ct(n("input",{"onUpdate:modelValue":t[2]||(t[2]=a=>J.value=a),type:"radio",class:"mode-check-input",value:"FINITE"},null,512),[[dt,J.value]]),t[11]||(t[11]=n("span",{class:"mode-check-text"},"执行固定轮次",-1)),t[12]||(t[12]=n("span",{class:"mode-hint-inline"},"按整批店铺重复执行指定次数",-1))]),n("label",Ks,[ct(n("input",{"onUpdate:modelValue":t[3]||(t[3]=a=>J.value=a),type:"radio",class:"mode-check-input",value:"INFINITE"},null,512),[[dt,J.value]]),t[13]||(t[13]=n("span",{class:"mode-check-text"},"无限执行",-1)),t[14]||(t[14]=n("span",{class:"mode-hint-inline"},"上一轮全部成功后立即开始下一轮",-1))]),J.value==="FINITE"?(i(),c("div",Vs,[t[15]||(t[15]=n("span",{class:"hint"},"轮次",-1)),C(s,{modelValue:ye.value,"onUpdate:modelValue":t[4]||(t[4]=a=>ye.value=a),min:1,max:9999,disabled:Ee.value||j.value},null,8,["modelValue","disabled"])])):y("",!0)]),S.value?(i(),c(L,{key:0},[t[17]||(t[17]=n("div",{class:"section-title"},[ve("ASIN文档 "),n("span",{class:"tag-badge"},"自定义模式")],-1)),n("div",Ws,[t[16]||(t[16]=n("div",{class:"hint"},"上传包含ASIN的表格文件,按文档内的ASIN进行跟价。",-1)),n("div",{class:"btns"},[n("button",{type:"button",class:"opt-btn",onClick:It},"选择ASIN文件"),n("button",{type:"button",class:"opt-btn",onClick:St},"选择文件夹")]),n("div",Hs,[R.value.length?(i(!0),c(L,{key:0},fe(R.value,(a,d)=>(i(),c("span",{key:d},v(a),1))),128)):(i(),c("span",zs,"暂未选择"))])])],64)):y("",!0),A.value?(i(),c(L,{key:1},[t[19]||(t[19]=n("div",{class:"section-title"},"店铺名称",-1)),n("div",Gs,[t[18]||(t[18]=n("div",{class:"hint"},"输入店铺名后点「确认」加入下方备选区。可同时配合上方模式使用。",-1)),n("div",Qs,[C(o,{modelValue:te.value,"onUpdate:modelValue":t[5]||(t[5]=a=>te.value=a),clearable:"",placeholder:"请输入店铺名称",onKeyup:os(Ze,["enter"])},null,8,["modelValue"]),n("button",{type:"button",class:"opt-btn",disabled:me.value,onClick:Ze},v(me.value?"保存中…":"确认"),9,Xs)])]),t[20]||(t[20]=n("div",{class:"section-title"},"备选店铺",-1)),Ie.value.length?(i(),c("div",Zs,[C(u,{data:Ie.value,"row-key":"id",height:"160",class:"candidate-table",onSelectionChange:$t},{default:z(()=>[C(l,{type:"selection",width:"42"}),C(l,{prop:"shopName",label:"店铺名","min-width":"120","show-overflow-tooltip":""}),C(l,{label:"操作",width:"72",align:"center"},{default:z(({row:a})=>[n("button",{type:"button",class:"link-danger",onClick:d=>Dt(a)},"删除",8,ea)]),_:1})]),_:1},8,["data"])])):(i(),c("div",Ys,"暂无备选店铺,请先输入并确认"))],64)):y("",!0),S.value?y("",!0):(i(),c(L,{key:2},[t[23]||(t[23]=n("div",{class:"section-title"},"处理国家与顺序",-1)),t[24]||(t[24]=n("p",{class:"hint country-pref-hint"}," 勾选需要处理的站点;拖拽调整顺序。设置会按当前登录用户保存。 ",-1)),n("div",ta,[(i(!0),c(L,null,fe(Ct.value,a=>(i(),c("label",{key:a.code,class:"country-check-row"},[n("input",{type:"checkbox",class:"country-check-input",checked:Tt(a.code),disabled:Xe(a.code),onChange:d=>Nt(a.code,d)},null,40,sa),n("span",aa,v(a.label)+"("+v(a.code)+")",1)]))),128))]),g.value.length?(i(),c("div",na,[t[22]||(t[22]=n("div",{class:"country-order-caption"},"已选顺序(拖拽 ⋮⋮ 调整)",-1)),n("div",oa,[(i(!0),c(L,null,fe(g.value,(a,d)=>(i(),c("div",{key:a,class:_e(["country-drag-row",{dragging:ne.value===d}]),draggable:"true",onDragstart:T=>Pt(d),onDragend:At,onDragover:t[6]||(t[6]=vt(()=>{},["prevent"])),onDrop:vt(T=>Rt(d),["prevent"])},[t[21]||(t[21]=n("span",{class:"drag-handle",title:"拖动排序"},"⋮⋮",-1)),n("span",ra,v(Qe(a))+"("+v(a)+")",1)],42,la))),128))])])):y("",!0),Pe.value?(i(),c("div",ua,"保存中…")):y("",!0)],64)),A.value?(i(),c("div",ia,[...t[25]||(t[25]=[n("span",{class:"mode-status-dot active"},null,-1),n("span",{class:"mode-status-text"},"商品状态模式:将在售(Active)ASIN纳入跟价,跳过ASIN由后台配置的店铺维度数据提供",-1)])])):y("",!0),n("div",ca,[n("button",{type:"button",class:"btn-run",disabled:he.value,onClick:Ft},v(he.value?"匹配中…":"匹配店铺"),9,da),n("button",{type:"button",class:"btn-run btn-queue",disabled:j.value||!Ne.value,onClick:Ht},v(j.value?"推送中…":"推送到 Python 队列"),9,va)]),t[29]||(t[29]=n("p",{class:"loading-msg"},[ve("上传ASIN文档和多选店铺"),n("strong",null,"可同时生效"),ve(",跟价结果合并输出。全量和自定义的区别仅在于ASIN来源不同。")],-1)),k.value?(i(),c("div",fa,[n("div",pa,"循环任务 ID:"+v(k.value.id),1),n("div",ma,"状态:"+v(k.value.status||"-"),1),n("div",ha,"进度:"+v(ht.value),1),n("div",ya,"当前店铺:"+v((k.value.currentShopIndex||0)+1)+"/"+v(k.value.totalShopCount||0),1),k.value.errorMessage?(i(),c("div",ka,v(k.value.errorMessage),1)):y("",!0),n("button",{type:"button",class:"opt-btn loop-stop-btn",disabled:!Ee.value||se.value,onClick:Wt},v(se.value?"停止中...":"停止循环"),9,ga)])):y("",!0),p.value?(i(),c("div",wa,[t[26]||(t[26]=n("div",{class:"section-title queue-debug-title"},"推送结果",-1)),n("div",_a,v(p.value),1),G.value?(i(),c("pre",ba,v(G.value),1)):y("",!0)])):y("",!0)]),n("section",Ia,[t[38]||(t[38]=n("div",{class:"panel-header"},"匹配与任务",-1)),n("div",Sa,[n("div",Ca,[n("div",Ta,[t[30]||(t[30]=n("span",{class:"summary-label"},"备选店铺数",-1)),n("strong",null,v(oe.value.candidateCount),1)]),n("div",Na,[t[31]||(t[31]=n("span",{class:"summary-label"},"已结束任务",-1)),n("strong",null,v(oe.value.processedTaskCount),1)]),n("div",Ea,[t[32]||(t[32]=n("span",{class:"summary-label"},"成功任务",-1)),n("strong",null,v(oe.value.successTaskCount),1)]),n("div",Pa,[t[33]||(t[33]=n("span",{class:"summary-label"},"失败任务",-1)),n("strong",null,v(oe.value.failedTaskCount),1)])]),t[37]||(t[37]=n("div",{class:"subsection-title"},"匹配结果",-1)),I.value.length?(i(),is(u,{key:1,data:I.value,"row-key":De,"highlight-current-row":!1,class:"result-table match-table"},{default:z(()=>[C(l,{prop:"shopName",label:"店铺名","min-width":"100"}),C(l,{label:"匹配",width:"72",align:"center"},{default:z(({row:a})=>[n("span",{class:_e(a.matched?"ok":"fail")},v(a.matched?"是":"否"),3)]),_:1}),C(l,{prop:"shopId",label:"店铺ID","min-width":"120","show-overflow-tooltip":""}),C(l,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),C(l,{prop:"companyName",label:"公司","min-width":"100","show-overflow-tooltip":""}),C(l,{label:"状态",width:"100","show-overflow-tooltip":""},{default:z(({row:a})=>[ve(v(Ut(a.matchStatus)),1)]),_:1}),C(l,{label:"说明","min-width":"140","show-overflow-tooltip":""},{default:z(({row:a})=>[ve(v(Bt(a)),1)]),_:1}),C(l,{label:"操作",width:"72",align:"center"},{default:z(({row:a})=>[n("button",{type:"button",class:"link-danger",onClick:d=>jt(a)},"删除",8,Ra)]),_:1})]),_:1},8,["data"])):(i(),c("div",Aa,"完成「匹配店铺」后,在此展示紫鸟索引匹配结果,供核对后再推送队列。")),n("div",xa,[t[36]||(t[36]=n("div",{class:"result-list-header"},[n("span",null,"处理记录")],-1)),Qt.value?(i(),c(L,{key:1},[Ue.value.length?(i(),c("div",$a,[t[34]||(t[34]=n("div",{class:"result-subsection-title"},"当前任务",-1)),n("ul",Da,[(i(!0),c(L,null,fe(Ue.value,a=>(i(),c("li",{key:`cur-${a.resultId}-${a.taskId}`,class:"task-item split-result-item"},[n("div",La,[a.roundIndex?(i(),c("div",Fa,"轮次:第 "+v(a.roundIndex)+" 轮",1)):y("",!0),n("span",{class:"id",title:a.shopName||""},v(a.shopName||"-"),9,Ua),n("div",Ba,"任务 ID:"+v(a.taskId??"-"),1),a.platform?(i(),c("div",Oa,"平台:"+v(a.platform),1)):y("",!0),a.error?(i(),c("div",qa,"错误:"+v(a.error),1)):y("",!0)]),n("div",ja,[n("span",{class:_e(["status",lt(a)])},v(ot(a)),3),rt(a)?(i(),c("button",{key:0,type:"button",class:"download",onClick:d=>ut(a)}," 下载 ",8,Ja)):y("",!0),n("button",{type:"button",class:"btn-delete",onClick:d=>it(a)},"删除",8,Ka)])]))),128))])])):y("",!0),Be.value.length?(i(),c("div",Va,[t[35]||(t[35]=n("div",{class:"result-subsection-title"},"历史记录",-1)),n("ul",Wa,[(i(!0),c(L,null,fe(Be.value,a=>(i(),c("li",{key:`his-${a.resultId}-${a.taskId}`,class:"task-item split-result-item"},[n("div",Ha,[a.roundIndex?(i(),c("div",za,"轮次:第 "+v(a.roundIndex)+" 轮",1)):y("",!0),n("span",{class:"id",title:a.shopName||""},v(a.shopName||"-"),9,Ga),n("div",Qa,"任务 ID:"+v(a.taskId??"-"),1),a.outputFilename?(i(),c("div",Xa,"文件:"+v(a.outputFilename),1)):y("",!0),a.error?(i(),c("div",Ya,"错误:"+v(a.error),1)):y("",!0)]),n("div",Za,[n("span",{class:_e(["status",lt(a)])},v(ot(a)),3),rt(a)?(i(),c("button",{key:0,type:"button",class:"download",onClick:d=>ut(a)}," 下载 ",8,en)):y("",!0),n("button",{type:"button",class:"btn-delete",onClick:d=>it(a)},"删除",8,tn)])]))),128))])])):y("",!0)],64)):(i(),c("div",Ma,"暂无处理记录。推送队列并等待 Python 回传后,将在此显示下载链接。"))])])])])])}}}),an=Ps(sn,[["__scopeId","data-v-c91dd406"]]);As(an).use(Rs).mount("#app"); diff --git a/app/assets/product-risk.js b/app/assets/product-risk.js index 94a5a7d..b47aef3 100644 --- a/app/assets/product-risk.js +++ b/app/assets/product-risk.js @@ -1 +1 @@ -import{d as mt,o as wt,M as _t,a as c,c as d,b as m,B as bt,e as n,ad as St,ae as Ct,t as f,af as E,ag as It,ah as Tt,y as M,F as O,r as H,ai as qe,n as Z,f as _,aj as Et,ak as Ae,al as Pt,am as Nt,g as v,h as ee,E as u,an as Rt,ao as Dt,ap as $t,aq as Ft,ar as Mt,as as Ot,at as Ut,au as Lt,av as Be,aw as qt,ax as At,ay as Bt,az as xt,s as jt,i as xe,aA as Vt,V as Kt,_ as Jt,q as Ht,u as Qt}from"./java-modules-DzYrjxib.js";/* empty css */import{L as zt}from"./listingFilters-BpGOU_pJ.js";import{c as Gt}from"./categorized-timers-JPA-olTr.js";const Wt={class:"page-shell module-page"},Xt={class:"main-content"},Yt={class:"left-panel"},Zt={class:"input-zone"},es={class:"input-row"},ts=["disabled"],ss={key:0,class:"empty-candidates"},as={key:1,class:"candidate-table-scroll"},ns=["onClick"],os={class:"country-pref-checks"},ls=["checked","disabled","onChange"],rs={class:"country-check-text"},us={key:2,class:"country-order-panel"},is={class:"country-order-list"},cs=["onDragstart","onDrop"],ds={class:"country-drag-label"},fs={key:3,class:"country-pref-status"},vs={class:"listing-filter-row"},ps={class:"run-row"},hs=["disabled"],ys=["disabled"],ks={key:4,class:"queue-debug-card"},gs={class:"queue-debug-line"},ms={key:0,class:"queue-debug-payload"},ws={class:"right-panel"},_s={class:"task-list-wrap"},bs={class:"clean-result-summary pr-summary"},Ss={class:"summary-card"},Cs={class:"summary-card"},Is={class:"summary-card"},Ts={class:"summary-card"},Es={key:0,class:"empty-tasks narrow"},Ps=["onClick"],Ns={class:"result-list-wrap"},Rs={key:0,class:"empty-tasks"},Ds={key:0,class:"result-subsection"},$s={class:"task-list clean-result-list"},Fs={class:"left split-result-main"},Ms=["title"],Os={class:"files"},Us={key:0,class:"files"},Ls={key:1,class:"files"},qs={class:"task-right split-result-actions"},As=["onClick"],Bs=["onClick"],xs={key:1,class:"result-subsection"},js={class:"task-list clean-result-list"},Vs={class:"left split-result-main"},Ks=["title"],Js={class:"files"},Hs={key:0,class:"files"},Qs={key:1,class:"files"},zs={class:"task-right split-result-actions"},Gs=["onClick"],Ws=["onClick"],Xs=mt({__name:"BrandProductRiskTab",setup(Zs){const U=v(""),te=v([]),fe=v([]),p=v([]),Q=v(!1),z=v(!1),G=v(!1),se=v(!1),ve=v(!1),y=v(""),L=v(""),pe=[{code:"DE",label:"德国"},{code:"UK",label:"英国"},{code:"FR",label:"法国"},{code:"IT",label:"意大利"},{code:"ES",label:"西班牙"}],h=v(["DE","UK","FR","IT","ES"]),D=v("SearchSuppressed"),q=v(null),ae=v(!1),ne=v(!1);let $=null;function he(e){return pe.find(s=>s.code===e)?.label??e}const je=ee(()=>{const e=h.value,t=new Set(e),s=e.map(l=>({code:l,label:he(l)})),o=pe.filter(l=>!t.has(l.code)).map(l=>({code:l.code,label:l.label}));return[...s,...o]});function Ve(e){return h.value.includes(e)}function ye(e){return h.value.length===1&&h.value[0]===e}function Ke(e,t){const s=t.target;if(s){if(!s.checked&&ye(e)){s.checked=!0,u.warning("至少保留 1 个国家");return}Je(e,s.checked)}}function Je(e,t){if(ne.value=!0,t)h.value.includes(e)||(h.value=[...h.value,e]);else{if(h.value.length<=1){u.warning("至少保留 1 个国家");return}h.value=h.value.filter(s=>s!==e)}ke()}function He(e){q.value=e}function Qe(){q.value=null}function ze(e){const t=q.value;if(q.value=null,t==null||t===e)return;ne.value=!0;const s=[...h.value],[o]=s.splice(t,1);s.splice(e,0,o),h.value=s,ke()}function ke(){$&&C.clearTimer("preference-save",$),$=C.setTimeout("preference-save",()=>{$=null,Ge()},450)}async function Ge(){if(!(h.value.length<1)){ae.value=!0;try{await Rt(h.value)}catch(e){u.error(e instanceof Error?e.message:"保存国家顺序失败")}finally{ae.value=!1}}}async function We(){try{const e=await Dt();if(ne.value)return;e?.country_codes?.length&&(h.value=[...e.country_codes])}catch{}}const A=v({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),P=v([]),k=v([]),N=v({}),g=v({}),S=v(null),oe=v(!1);let b=!1;const C=Gt("product-risk");function W(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function ge(){return`product-risk:tasks:${W()}`}function me(){return`product-risk:task-status:${W()}`}function we(){return`product-risk:tasks-batch-snapshot:${W()}`}function _e(){return`product-risk:matched-items:${W()}`}function X(e,t,s){if(!(typeof window>"u"))try{s?window.localStorage.removeItem(e):window.localStorage.setItem(e,JSON.stringify(t))}catch{}}function Xe(){try{const e=typeof window<"u"?window.localStorage.getItem(me()):null;if(!e)return;const t=JSON.parse(e),s={};for(const[o,l]of Object.entries(t)){const r=Number(o);r>0&&typeof l=="string"&&(s[r]=l)}N.value=s}catch{}}function le(){X(me(),N.value,Object.keys(N.value).length===0)}function Ye(){try{const e=typeof window<"u"?window.localStorage.getItem(we()):null;if(!e)return;const t=JSON.parse(e),s={};for(const[o,l]of Object.entries(t)){const r=Number(o);r>0&&l&&typeof l=="object"&&(s[r]=l)}g.value=s}catch{}}function B(){X(we(),g.value,Object.keys(g.value).length===0)}function Ze(){try{const e=typeof window<"u"?window.localStorage.getItem(_e()):null;if(!e)return;const t=JSON.parse(e);Array.isArray(t)&&(p.value=t)}catch{}}function x(){X(_e(),p.value,p.value.length===0)}function j(e){const t=(e.shopName||"").trim(),s=e.shopId??"";return`${t}${s}`}function be(e){const t=e instanceof Error?e.message:String(e||"");return/记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(t)}function F(e){if(!e.length)return;const t=new Set(e.map(s=>j(s)));p.value=p.value.filter(s=>!t.has(j(s))),x()}function et(e){P.value=P.value.filter(t=>!(e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId))}async function tt(e){const t=j(e),s=[...p.value];p.value=p.value.filter(l=>j(l)!==t),x();const o=(e.shopName||"").trim();if(!o){u.success("已从匹配结果中移除");return}try{(await $t(o))?.removed&&(await T(),await I(),V()),u.success("已从匹配结果中移除")}catch(l){if(be(l)){await T(),await I(),V(),u.success("后端记录已不存在,已同步移除本地记录");return}p.value=s,x(),u.error(l instanceof Error?l.message:"同步后端失败")}}function V(){for(const e of[...k.value])P.value.some(s=>s.taskId===e)||R(e)}async function Se(e){try{if(e.resultId!=null&&e.resultId>0)await Ft(e.resultId);else if(e.taskId!=null&&e.taskId>0)await Mt(e.taskId);else{u.warning("无法删除:缺少记录标识");return}e.taskId!=null&&e.taskId>0&&R(e.taskId),F([e]),await T(),await I(),V(),u.success("已删除")}catch(t){if(be(t)){e.taskId!=null&&e.taskId>0&&R(e.taskId),F([e]),et(e),await I(),V(),u.success("后端记录已不存在,已同步移除本地记录");return}u.error(t instanceof Error?t.message:"删除失败")}}function st(){try{const e=typeof window<"u"?window.localStorage.getItem(ge()):null;if(!e){k.value=[];return}const t=JSON.parse(e);k.value=Array.isArray(t)?t.filter(s=>typeof s=="number"):[]}catch{k.value=[]}}function Ce(){X(ge(),k.value,k.value.length===0)}function Ie(e){k.value.includes(e)||(k.value=[...k.value,e],Ce())}function R(e){if(k.value=k.value.filter(t=>t!==e),Ce(),delete N.value[e],le(),g.value[e]){const t={...g.value};delete t[e],g.value=t,B()}}function at(e){fe.value=e||[]}async function I(){try{A.value=await Ot()}catch{}}async function re(){try{te.value=await Ut(),await I()}catch(e){u.error(e instanceof Error?e.message:"加载备选失败")}}async function T(){try{P.value=(await Lt()).items||[]}catch{P.value=[]}}function Te(e){return e&&N.value[e]||""}function Ee(e){const t=Te(e);return t==="SUCCESS"||t==="FAILED"}const ue=ee(()=>{const e=P.value.filter(s=>s.taskId&&k.value.includes(s.taskId)&&!Ee(s.taskId)),t=new Set(e.map(s=>s.taskId).filter(s=>typeof s=="number"));for(const s of k.value){if(t.has(s))continue;const r=(g.value[s]?.items||[])[0];r&&e.push(r)}return e}),ie=ee(()=>P.value.filter(e=>!e.taskId||!k.value.includes(e.taskId)||Ee(e.taskId))),nt=ee(()=>ue.value.length>0||ie.value.length>0),ot=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"];function ce(e){return b?Promise.resolve():C.sleep("queue-wait",e)}function lt(){C.clearCategory("queue-wait")}function Pe(e){const t=(e instanceof Error?e.message:String(e||"")).toLowerCase();return ot.some(s=>t.includes(s.toLowerCase()))}async function Ne(e,t=10){let s=0;for(;;){if(b)throw new Error("component disposed");try{return await Vt(e)}catch(o){if(s+=1,!Pe(o)||s>=t)throw o;y.value=`后端服务暂时不可用,正在重试创建任务(${s}/${t})...`,await ce(K())}}}async function Re(){const e=k.value.filter(t=>t>0);if(e.length)try{const t=await Be(e);let s=!1;const o={...g.value};for(const l of t.items||[]){const r=l.task?.id,i=l.task?.status;if(typeof r=="number"&&r>0){const a=o[r];o[r]=a?{...a,task:{...a.task||{},...l.task||{}}}:l,i&&(N.value[r]=i,(i==="SUCCESS"||i==="FAILED")&&(R(r),s=!0))}}g.value=o,B(),le(),s&&(await T(),await I())}catch{}}function K(){return Kt()}function De(e=!1){if(S.value){if(!e)return;C.clearTimer("task-poll",S.value),S.value=null}const t=async()=>{if(S.value=null,!b){if(oe.value){De();return}if(k.value.length){oe.value=!0;try{await Re()}finally{oe.value=!1}!b&&k.value.length>0&&(S.value=C.setTimeout("task-poll",t,K()))}}};b||(e?t():S.value=C.setTimeout("task-poll",t,K()))}function J(e=!1){S.value&&!e||De(e)}function rt(){S.value&&(C.clearTimer("task-poll",S.value),S.value=null)}async function $e(e){let t=0;const s=30;for(;;){if(b)return"STOPPED";try{const o=await Be([e]);t>0&&(y.value=`任务 ${e} 后端已恢复,继续等待执行结果...`),t=0;const l=(o.items||[]).find(i=>i.task?.id===e),r=l?.task?.status||"";if(l){const i=g.value[e];g.value={...g.value,[e]:i?{...i,task:{...i.task||{},...l.task||{}}}:l},B()}if(r&&(N.value[e]=r,le()),r==="SUCCESS"||r==="FAILED")return R(e),await T(),await I(),r}catch(o){if(!Pe(o))throw o;if(t+=1,t>=s)throw new Error(`任务 ${e} 等待后端恢复超时,请稍后手动刷新查看状态`);y.value=`任务 ${e} 运行中,正在等待后端服务恢复(${t}/${s})...`,(t===1||t%5===0)&&u.warning(`任务 ${e} 运行中,后端服务暂时不可用,正在自动重试`),await ce(K());continue}await ce(K())}}async function Fe(){const e=U.value.trim();if(!e){u.warning("请输入店铺名称");return}Q.value=!0;try{await qt(e),U.value="",await re(),u.success("已加入备选")}catch(t){u.error(t instanceof Error?t.message:"保存失败")}finally{Q.value=!1}}async function ut(e){try{await At(e.id),await re(),p.value=[],x(),u.success("已删除")}catch(t){u.error(t instanceof Error?t.message:"删除失败")}}function it(){const e=new Set,t=U.value.trim();t&&e.add(t);for(const s of fe.value)s?.shop_name?.trim()&&e.add(s.shop_name.trim());return[...e]}function ct(e,t){const s=new Map;for(const r of t){const i=(r.shopName||"").trim();i&&s.set(i,r)}const o=new Set,l=[];for(const r of e){const i=(r.shopName||"").trim();i&&s.has(i)?(l.push(s.get(i)),o.add(i)):l.push(r)}for(const r of t){const i=(r.shopName||"").trim();if(!i){l.push(r);continue}o.has(i)||(l.push(r),o.add(i))}return l}async function dt(){const e=it();if(!e.length){u.warning("请勾选备选店铺,或在输入框中填写店名(可与勾选合并)");return}z.value=!0;try{const s=(await Bt(e)).items||[];p.value=ct(p.value,s),x(),s.length?u.success(`本次匹配 ${s.length} 个店铺名,表格共 ${p.value.length} 条`):u.warning("未返回匹配结果")}catch(t){u.error(t instanceof Error?t.message:"匹配失败")}finally{z.value=!1}}function de(e){const t=e.taskId;return t?Te(t)||e.taskStatus||"":e.taskStatus||""}function Me(e){const t=de(e);return t==="SUCCESS"?"已完成":t==="FAILED"?"失败":t==="RUNNING"?"执行中":e.success?"已完成":"等待中"}function Oe(e){const t=de(e);return t==="SUCCESS"||e.success?"success":t==="FAILED"?"failed":"running"}function Ue(e){return!e.resultId||!e.fileReady&&!e.downloadUrl?!1:de(e)==="SUCCESS"||e.success===!0}async function Le(e){if(!e.resultId)return;const t=xt(e.resultId),s=e.outputFilename||`${e.shopName||"result"}.zip`,o=await jt(t,s,`product-risk:${e.resultId}`);o.success?u.success(`已保存:${o.path||s}`):o.error&&o.error!=="用户取消"&&u.error(o.error)}function ft(e){const t=(e||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[t]||t||"—"}function vt(e){const t=(e.matchMessage||"").trim();return t||(e.matched&&e.matchStatus==="MATCHED"?"紫鸟索引已命中,可推送队列;打开店铺地址由 Python 侧处理":e.matched?"已关联索引,请结合状态列查看是否可推送":"未命中或未就绪,请检查店铺名与索引刷新")}async function pt(){ve.value=!0,await gt()}function ht(){return p.value.find(e=>e.matched)}function yt(){return D.value==="SearchSuppressed"||D.value==="DetailPageRemoved"}async function kt(e){const t=xe();if(!t?.enqueue_json){u.error("当前环境未启用 pywebview enqueue_json");return}const s=await Ne(e),o=s.taskId;g.value={...g.value,[o]:{task:{id:o,status:"RUNNING"},items:s.items}},B(),Ie(o),J(!0);const l={type:"product-risk-resolve-run",ts:Date.now(),data:{taskId:o,items:e,country_codes:[...h.value],risk_listing_filter:D.value}};L.value=JSON.stringify(l,null,2);const r=await t.enqueue_json(l);if(!r?.success)throw R(o),new Error("任务 "+o+" 推送失败:"+(r?.error||"未知错误"));F(e),y.value="任务 "+o+" 已入队,共 "+e.length+" 个店铺,等待执行完成...";const i=await $e(o);if(y.value="任务 "+o+(i==="SUCCESS"?" 已完成":" 执行失败"),i!=="SUCCESS")throw new Error(y.value)}async function gt(){if(b||se.value)return;if(!p.value.length){u.warning("请先匹配店铺");return}const e=xe();if(!e?.enqueue_json){u.error("当前环境未启用 pywebview enqueue_json");return}const t=p.value.filter(l=>l.matched);if(!t.length){u.warning("没有已匹配的店铺可推送");return}se.value=!0,G.value=!0,L.value="";let s=0,o=0;try{if(yt()){await kt(t),u.success("店铺推送已完成:成功 "+t.length+" 条,失败 0 条"),await T(),J(!0);return}let l=0;for(;!b&&ve.value;){const r=ht();if(!r)break;l+=1;try{const i=await Ne([r]),a=i.taskId;g.value={...g.value,[a]:{task:{id:a,status:"RUNNING"},items:i.items}},B(),Ie(a),J(!0);const w={type:"product-risk-resolve-run",ts:Date.now(),data:{taskId:a,items:[r],country_codes:[...h.value],risk_listing_filter:D.value}};L.value=JSON.stringify(w,null,2);const Y=await e.enqueue_json(w);if(!Y?.success){R(a),o+=1,y.value="第 "+l+" 条推送失败:"+(Y?.error||"未知错误")+",已自动继续下一条",u.error(y.value),F([r]);continue}if(F([r]),y.value="任务 "+a+" 已入队,等待执行完成...",await $e(a)!=="SUCCESS"){o+=1,y.value="任务 "+a+" 执行失败,已自动继续下一条",u.error(y.value);continue}s+=1,y.value="任务 "+a+" 已完成"}catch(i){if(b)break;o+=1,y.value="第 "+l+" 条任务处理失败,已自动继续下一条:"+(i instanceof Error?i.message:"未知错误"),u.error(y.value),F([r]);continue}}(s>0||o>0)&&u.success("店铺推送已完成:成功 "+s+" 条,失败 "+o+" 条"),await T(),J(!0)}catch(l){if(b)return;y.value=l instanceof Error?l.message:"推送异常",u.error(y.value)}finally{se.value=!1,G.value=!1}}return wt(()=>{st(),Xe(),Ye(),Ze(),re().catch(()=>{}),We().catch(()=>{}),T().then(()=>(V(),Re())).catch(()=>{}),I().catch(()=>{}),k.value.length&&J(!0)}),_t(()=>{b=!0,rt(),lt(),C.clearScope(),$&&C.clearTimer("preference-save",$)}),(e,t)=>{const s=Ct,o=It,l=Tt,r=Pt,i=Nt;return c(),d("div",Wt,[m(bt,{active:"product-risk"}),n("div",Xt,[n("aside",Yt,[t[7]||(t[7]=n("div",{class:"section-title"},"店铺名称",-1)),n("div",Zt,[t[3]||(t[3]=n("div",{class:"hint"},"输入店铺名后点「确认」加入下方备选区(按当前登录用户保存)。仅索引可命中的店铺可入库。勾选备选后点「匹配店铺」,再「推送到 Python 队列」。",-1)),n("div",es,[m(s,{modelValue:U.value,"onUpdate:modelValue":t[0]||(t[0]=a=>U.value=a),clearable:"",placeholder:"请输入店铺名称",onKeyup:St(Fe,["enter"])},null,8,["modelValue"]),n("button",{type:"button",class:"opt-btn",disabled:Q.value,onClick:Fe},f(Q.value?"保存中…":"确认"),9,ts)])]),t[8]||(t[8]=n("div",{class:"section-title"},"备选区域",-1)),te.value.length?(c(),d("div",as,[m(l,{data:te.value,"row-key":"id",height:"240",class:"candidate-table",onSelectionChange:at},{default:E(()=>[m(o,{type:"selection",width:"42"}),m(o,{prop:"shop_name",label:"店铺名","min-width":"120","show-overflow-tooltip":""}),m(o,{label:"操作",width:"72",align:"center"},{default:E(({row:a})=>[n("button",{type:"button",class:"link-danger",onClick:w=>ut(a)},"删除",8,ns)]),_:1})]),_:1},8,["data"])])):(c(),d("div",ss,"暂无备选店铺,请先输入并确认")),t[9]||(t[9]=n("div",{class:"section-title"},"处理国家与顺序",-1)),t[10]||(t[10]=n("p",{class:"hint country-pref-hint"},[M(" 勾选需要处理的站点(可只选 2~3 国);上方勾选区"),n("strong",null,"先按已选顺序"),M("排列,其余未选国家排在后面。拖拽下方列表调整顺序后会与上方同步。设置会按当前登录用户保存。 ")],-1)),n("div",os,[(c(!0),d(O,null,H(je.value,a=>(c(),d("label",{key:a.code,class:"country-check-row"},[n("input",{type:"checkbox",class:"country-check-input",checked:Ve(a.code),disabled:ye(a.code),onChange:w=>Ke(a.code,w)},null,40,ls),n("span",rs,f(a.label)+"("+f(a.code)+")",1)]))),128))]),h.value.length?(c(),d("div",us,[t[5]||(t[5]=n("div",{class:"country-order-caption"},"已选顺序(拖拽 ⋮⋮ 调整)",-1)),n("div",is,[(c(!0),d(O,null,H(h.value,(a,w)=>(c(),d("div",{key:a,class:Z(["country-drag-row",{dragging:q.value===w}]),draggable:"true",onDragstart:Y=>He(w),onDragend:Qe,onDragover:t[1]||(t[1]=qe(()=>{},["prevent"])),onDrop:qe(Y=>ze(w),["prevent"])},[t[4]||(t[4]=n("span",{class:"drag-handle",title:"拖动排序"},"⋮⋮",-1)),n("span",ds,f(he(a))+"("+f(a)+")",1)],42,cs))),128))])])):_("",!0),ae.value?(c(),d("div",fs,"保存中…")):_("",!0),t[11]||(t[11]=n("div",{class:"section-title"},"商品列表筛选",-1)),t[12]||(t[12]=n("p",{class:"hint listing-filter-hint"},"与「推送到 Python 队列」一并下发,供 Python 区分处理场景。",-1)),n("div",vs,[m(i,{modelValue:D.value,"onUpdate:modelValue":t[2]||(t[2]=a=>D.value=a),class:"listing-filter-select",teleported:"",placeholder:"选择筛选类型"},{default:E(()=>[(c(!0),d(O,null,H(Et(zt),a=>(c(),Ae(r,{key:a.value,label:a.label,value:a.value},null,8,["label","value"]))),128))]),_:1},8,["modelValue"])]),n("div",ps,[n("button",{type:"button",class:"btn-run",disabled:z.value,onClick:dt},f(z.value?"匹配中…":"匹配店铺"),9,hs),n("button",{type:"button",class:"btn-run btn-queue",disabled:G.value||!p.value.length,onClick:pt},f(G.value?"推送中…":"推送到 Python 队列"),9,ys)]),t[13]||(t[13]=n("p",{class:"loading-msg"},[M("在搜索结果中禁止显示、详情页面已删除会把匹配店铺合并为一个任务入队,避免同时打开多个紫鸟窗口;其它筛选仍按店铺逐条入队。Python 每处理完一店可 POST "),n("code",null,"/api/product-risk-resolve/tasks/{taskId}/result"),M("(可多次,每次可只含已完成的店铺);全部完成后任务结束。前端轮询任务状态。 ")],-1)),y.value?(c(),d("div",ks,[t[6]||(t[6]=n("div",{class:"section-title queue-debug-title"},"推送结果",-1)),n("div",gs,f(y.value),1),L.value?(c(),d("pre",ms,f(L.value),1)):_("",!0)])):_("",!0)]),n("section",ws,[t[22]||(t[22]=n("div",{class:"panel-header"},"匹配与任务",-1)),n("div",_s,[n("div",bs,[n("div",Ss,[t[14]||(t[14]=n("span",{class:"summary-label"},"备选店铺数",-1)),n("strong",null,f(A.value.candidateCount),1)]),n("div",Cs,[t[15]||(t[15]=n("span",{class:"summary-label"},"已结束任务",-1)),n("strong",null,f(A.value.processedTaskCount),1)]),n("div",Is,[t[16]||(t[16]=n("span",{class:"summary-label"},"成功任务",-1)),n("strong",null,f(A.value.successTaskCount),1)]),n("div",Ts,[t[17]||(t[17]=n("span",{class:"summary-label"},"失败任务",-1)),n("strong",null,f(A.value.failedTaskCount),1)])]),t[21]||(t[21]=n("div",{class:"subsection-title"},"匹配结果",-1)),p.value.length?(c(),Ae(l,{key:1,data:p.value,"row-key":j,"highlight-current-row":!1,class:"result-table match-table"},{default:E(()=>[m(o,{prop:"shopName",label:"店铺名","min-width":"100"}),m(o,{label:"匹配",width:"72",align:"center"},{default:E(({row:a})=>[n("span",{class:Z(a.matched?"ok":"fail")},f(a.matched?"是":"否"),3)]),_:1}),m(o,{prop:"shopId",label:"店铺ID","min-width":"120","show-overflow-tooltip":""}),m(o,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),m(o,{prop:"companyName",label:"公司","min-width":"100","show-overflow-tooltip":""}),m(o,{label:"状态",width:"100","show-overflow-tooltip":""},{default:E(({row:a})=>[M(f(ft(a.matchStatus)),1)]),_:1}),m(o,{label:"说明","min-width":"140","show-overflow-tooltip":""},{default:E(({row:a})=>[M(f(vt(a)),1)]),_:1}),m(o,{label:"操作",width:"72",align:"center"},{default:E(({row:a})=>[n("button",{type:"button",class:"link-danger",onClick:w=>tt(a)},"删除",8,Ps)]),_:1})]),_:1},8,["data"])):(c(),d("div",Es,"完成「匹配店铺」后,在此展示紫鸟索引匹配结果,供核对后再推送队列。")),n("div",Ns,[t[20]||(t[20]=n("div",{class:"result-list-header"},[n("span",null,"处理记录")],-1)),nt.value?(c(),d(O,{key:1},[ue.value.length?(c(),d("div",Ds,[t[18]||(t[18]=n("div",{class:"result-subsection-title"},"当前任务",-1)),n("ul",$s,[(c(!0),d(O,null,H(ue.value,a=>(c(),d("li",{key:`cur-${a.resultId}-${a.taskId}`,class:"task-item split-result-item"},[n("div",Fs,[n("span",{class:"id",title:a.shopName||""},f(a.shopName||"-"),9,Ms),n("div",Os,"任务 ID:"+f(a.taskId??"-"),1),a.platform?(c(),d("div",Us,"平台:"+f(a.platform),1)):_("",!0),a.error?(c(),d("div",Ls,"错误:"+f(a.error),1)):_("",!0)]),n("div",qs,[n("span",{class:Z(["status",Oe(a)])},f(Me(a)),3),Ue(a)?(c(),d("button",{key:0,type:"button",class:"download",onClick:w=>Le(a)}," 下载 ",8,As)):_("",!0),n("button",{type:"button",class:"btn-delete",onClick:w=>Se(a)},"删除",8,Bs)])]))),128))])])):_("",!0),ie.value.length?(c(),d("div",xs,[t[19]||(t[19]=n("div",{class:"result-subsection-title"},"历史记录",-1)),n("ul",js,[(c(!0),d(O,null,H(ie.value,a=>(c(),d("li",{key:`his-${a.resultId}-${a.taskId}`,class:"task-item split-result-item"},[n("div",Vs,[n("span",{class:"id",title:a.shopName||""},f(a.shopName||"-"),9,Ks),n("div",Js,"任务 ID:"+f(a.taskId??"-"),1),a.outputFilename?(c(),d("div",Hs,"文件:"+f(a.outputFilename),1)):_("",!0),a.error?(c(),d("div",Qs,"错误:"+f(a.error),1)):_("",!0)]),n("div",zs,[n("span",{class:Z(["status",Oe(a)])},f(Me(a)),3),Ue(a)?(c(),d("button",{key:0,type:"button",class:"download",onClick:w=>Le(a)}," 下载 ",8,Gs)):_("",!0),n("button",{type:"button",class:"btn-delete",onClick:w=>Se(a)},"删除",8,Ws)])]))),128))])])):_("",!0)],64)):(c(),d("div",Rs,"暂无处理记录。推送队列并等待 Python 回传后,将在此显示下载链接。"))])])])])])}}}),Ys=Jt(Xs,[["__scopeId","data-v-7520aec4"]]);Ht(Ys).use(Qt).mount("#app"); +import{d as mt,o as wt,M as _t,a as c,c as d,b as m,B as bt,e as n,ad as St,ae as Ct,t as f,af as E,ag as It,ah as Tt,y as M,F as O,r as H,ai as qe,n as Z,f as _,aj as Et,ak as Ae,al as Pt,am as Nt,g as v,h as ee,E as u,an as Rt,ao as Dt,ap as $t,aq as Ft,ar as Mt,as as Ot,at as Ut,au as Lt,av as Be,aw as qt,ax as At,ay as Bt,az as xt,s as jt,i as xe,aA as Vt,V as Kt,_ as Jt,q as Ht,u as Qt}from"./java-modules-B8c-YG5x.js";/* empty css */import{L as zt}from"./listingFilters-BpGOU_pJ.js";import{c as Gt}from"./categorized-timers-JPA-olTr.js";const Wt={class:"page-shell module-page"},Xt={class:"main-content"},Yt={class:"left-panel"},Zt={class:"input-zone"},es={class:"input-row"},ts=["disabled"],ss={key:0,class:"empty-candidates"},as={key:1,class:"candidate-table-scroll"},ns=["onClick"],os={class:"country-pref-checks"},ls=["checked","disabled","onChange"],rs={class:"country-check-text"},us={key:2,class:"country-order-panel"},is={class:"country-order-list"},cs=["onDragstart","onDrop"],ds={class:"country-drag-label"},fs={key:3,class:"country-pref-status"},vs={class:"listing-filter-row"},ps={class:"run-row"},hs=["disabled"],ys=["disabled"],ks={key:4,class:"queue-debug-card"},gs={class:"queue-debug-line"},ms={key:0,class:"queue-debug-payload"},ws={class:"right-panel"},_s={class:"task-list-wrap"},bs={class:"clean-result-summary pr-summary"},Ss={class:"summary-card"},Cs={class:"summary-card"},Is={class:"summary-card"},Ts={class:"summary-card"},Es={key:0,class:"empty-tasks narrow"},Ps=["onClick"],Ns={class:"result-list-wrap"},Rs={key:0,class:"empty-tasks"},Ds={key:0,class:"result-subsection"},$s={class:"task-list clean-result-list"},Fs={class:"left split-result-main"},Ms=["title"],Os={class:"files"},Us={key:0,class:"files"},Ls={key:1,class:"files"},qs={class:"task-right split-result-actions"},As=["onClick"],Bs=["onClick"],xs={key:1,class:"result-subsection"},js={class:"task-list clean-result-list"},Vs={class:"left split-result-main"},Ks=["title"],Js={class:"files"},Hs={key:0,class:"files"},Qs={key:1,class:"files"},zs={class:"task-right split-result-actions"},Gs=["onClick"],Ws=["onClick"],Xs=mt({__name:"BrandProductRiskTab",setup(Zs){const U=v(""),te=v([]),fe=v([]),p=v([]),Q=v(!1),z=v(!1),G=v(!1),se=v(!1),ve=v(!1),y=v(""),L=v(""),pe=[{code:"DE",label:"德国"},{code:"UK",label:"英国"},{code:"FR",label:"法国"},{code:"IT",label:"意大利"},{code:"ES",label:"西班牙"}],h=v(["DE","UK","FR","IT","ES"]),D=v("SearchSuppressed"),q=v(null),ae=v(!1),ne=v(!1);let $=null;function he(e){return pe.find(s=>s.code===e)?.label??e}const je=ee(()=>{const e=h.value,t=new Set(e),s=e.map(l=>({code:l,label:he(l)})),o=pe.filter(l=>!t.has(l.code)).map(l=>({code:l.code,label:l.label}));return[...s,...o]});function Ve(e){return h.value.includes(e)}function ye(e){return h.value.length===1&&h.value[0]===e}function Ke(e,t){const s=t.target;if(s){if(!s.checked&&ye(e)){s.checked=!0,u.warning("至少保留 1 个国家");return}Je(e,s.checked)}}function Je(e,t){if(ne.value=!0,t)h.value.includes(e)||(h.value=[...h.value,e]);else{if(h.value.length<=1){u.warning("至少保留 1 个国家");return}h.value=h.value.filter(s=>s!==e)}ke()}function He(e){q.value=e}function Qe(){q.value=null}function ze(e){const t=q.value;if(q.value=null,t==null||t===e)return;ne.value=!0;const s=[...h.value],[o]=s.splice(t,1);s.splice(e,0,o),h.value=s,ke()}function ke(){$&&C.clearTimer("preference-save",$),$=C.setTimeout("preference-save",()=>{$=null,Ge()},450)}async function Ge(){if(!(h.value.length<1)){ae.value=!0;try{await Rt(h.value)}catch(e){u.error(e instanceof Error?e.message:"保存国家顺序失败")}finally{ae.value=!1}}}async function We(){try{const e=await Dt();if(ne.value)return;e?.country_codes?.length&&(h.value=[...e.country_codes])}catch{}}const A=v({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),P=v([]),k=v([]),N=v({}),g=v({}),S=v(null),oe=v(!1);let b=!1;const C=Gt("product-risk");function W(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function ge(){return`product-risk:tasks:${W()}`}function me(){return`product-risk:task-status:${W()}`}function we(){return`product-risk:tasks-batch-snapshot:${W()}`}function _e(){return`product-risk:matched-items:${W()}`}function X(e,t,s){if(!(typeof window>"u"))try{s?window.localStorage.removeItem(e):window.localStorage.setItem(e,JSON.stringify(t))}catch{}}function Xe(){try{const e=typeof window<"u"?window.localStorage.getItem(me()):null;if(!e)return;const t=JSON.parse(e),s={};for(const[o,l]of Object.entries(t)){const r=Number(o);r>0&&typeof l=="string"&&(s[r]=l)}N.value=s}catch{}}function le(){X(me(),N.value,Object.keys(N.value).length===0)}function Ye(){try{const e=typeof window<"u"?window.localStorage.getItem(we()):null;if(!e)return;const t=JSON.parse(e),s={};for(const[o,l]of Object.entries(t)){const r=Number(o);r>0&&l&&typeof l=="object"&&(s[r]=l)}g.value=s}catch{}}function B(){X(we(),g.value,Object.keys(g.value).length===0)}function Ze(){try{const e=typeof window<"u"?window.localStorage.getItem(_e()):null;if(!e)return;const t=JSON.parse(e);Array.isArray(t)&&(p.value=t)}catch{}}function x(){X(_e(),p.value,p.value.length===0)}function j(e){const t=(e.shopName||"").trim(),s=e.shopId??"";return`${t}${s}`}function be(e){const t=e instanceof Error?e.message:String(e||"");return/记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(t)}function F(e){if(!e.length)return;const t=new Set(e.map(s=>j(s)));p.value=p.value.filter(s=>!t.has(j(s))),x()}function et(e){P.value=P.value.filter(t=>!(e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId))}async function tt(e){const t=j(e),s=[...p.value];p.value=p.value.filter(l=>j(l)!==t),x();const o=(e.shopName||"").trim();if(!o){u.success("已从匹配结果中移除");return}try{(await $t(o))?.removed&&(await T(),await I(),V()),u.success("已从匹配结果中移除")}catch(l){if(be(l)){await T(),await I(),V(),u.success("后端记录已不存在,已同步移除本地记录");return}p.value=s,x(),u.error(l instanceof Error?l.message:"同步后端失败")}}function V(){for(const e of[...k.value])P.value.some(s=>s.taskId===e)||R(e)}async function Se(e){try{if(e.resultId!=null&&e.resultId>0)await Ft(e.resultId);else if(e.taskId!=null&&e.taskId>0)await Mt(e.taskId);else{u.warning("无法删除:缺少记录标识");return}e.taskId!=null&&e.taskId>0&&R(e.taskId),F([e]),await T(),await I(),V(),u.success("已删除")}catch(t){if(be(t)){e.taskId!=null&&e.taskId>0&&R(e.taskId),F([e]),et(e),await I(),V(),u.success("后端记录已不存在,已同步移除本地记录");return}u.error(t instanceof Error?t.message:"删除失败")}}function st(){try{const e=typeof window<"u"?window.localStorage.getItem(ge()):null;if(!e){k.value=[];return}const t=JSON.parse(e);k.value=Array.isArray(t)?t.filter(s=>typeof s=="number"):[]}catch{k.value=[]}}function Ce(){X(ge(),k.value,k.value.length===0)}function Ie(e){k.value.includes(e)||(k.value=[...k.value,e],Ce())}function R(e){if(k.value=k.value.filter(t=>t!==e),Ce(),delete N.value[e],le(),g.value[e]){const t={...g.value};delete t[e],g.value=t,B()}}function at(e){fe.value=e||[]}async function I(){try{A.value=await Ot()}catch{}}async function re(){try{te.value=await Ut(),await I()}catch(e){u.error(e instanceof Error?e.message:"加载备选失败")}}async function T(){try{P.value=(await Lt()).items||[]}catch{P.value=[]}}function Te(e){return e&&N.value[e]||""}function Ee(e){const t=Te(e);return t==="SUCCESS"||t==="FAILED"}const ue=ee(()=>{const e=P.value.filter(s=>s.taskId&&k.value.includes(s.taskId)&&!Ee(s.taskId)),t=new Set(e.map(s=>s.taskId).filter(s=>typeof s=="number"));for(const s of k.value){if(t.has(s))continue;const r=(g.value[s]?.items||[])[0];r&&e.push(r)}return e}),ie=ee(()=>P.value.filter(e=>!e.taskId||!k.value.includes(e.taskId)||Ee(e.taskId))),nt=ee(()=>ue.value.length>0||ie.value.length>0),ot=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"];function ce(e){return b?Promise.resolve():C.sleep("queue-wait",e)}function lt(){C.clearCategory("queue-wait")}function Pe(e){const t=(e instanceof Error?e.message:String(e||"")).toLowerCase();return ot.some(s=>t.includes(s.toLowerCase()))}async function Ne(e,t=10){let s=0;for(;;){if(b)throw new Error("component disposed");try{return await Vt(e)}catch(o){if(s+=1,!Pe(o)||s>=t)throw o;y.value=`后端服务暂时不可用,正在重试创建任务(${s}/${t})...`,await ce(K())}}}async function Re(){const e=k.value.filter(t=>t>0);if(e.length)try{const t=await Be(e);let s=!1;const o={...g.value};for(const l of t.items||[]){const r=l.task?.id,i=l.task?.status;if(typeof r=="number"&&r>0){const a=o[r];o[r]=a?{...a,task:{...a.task||{},...l.task||{}}}:l,i&&(N.value[r]=i,(i==="SUCCESS"||i==="FAILED")&&(R(r),s=!0))}}g.value=o,B(),le(),s&&(await T(),await I())}catch{}}function K(){return Kt()}function De(e=!1){if(S.value){if(!e)return;C.clearTimer("task-poll",S.value),S.value=null}const t=async()=>{if(S.value=null,!b){if(oe.value){De();return}if(k.value.length){oe.value=!0;try{await Re()}finally{oe.value=!1}!b&&k.value.length>0&&(S.value=C.setTimeout("task-poll",t,K()))}}};b||(e?t():S.value=C.setTimeout("task-poll",t,K()))}function J(e=!1){S.value&&!e||De(e)}function rt(){S.value&&(C.clearTimer("task-poll",S.value),S.value=null)}async function $e(e){let t=0;const s=30;for(;;){if(b)return"STOPPED";try{const o=await Be([e]);t>0&&(y.value=`任务 ${e} 后端已恢复,继续等待执行结果...`),t=0;const l=(o.items||[]).find(i=>i.task?.id===e),r=l?.task?.status||"";if(l){const i=g.value[e];g.value={...g.value,[e]:i?{...i,task:{...i.task||{},...l.task||{}}}:l},B()}if(r&&(N.value[e]=r,le()),r==="SUCCESS"||r==="FAILED")return R(e),await T(),await I(),r}catch(o){if(!Pe(o))throw o;if(t+=1,t>=s)throw new Error(`任务 ${e} 等待后端恢复超时,请稍后手动刷新查看状态`);y.value=`任务 ${e} 运行中,正在等待后端服务恢复(${t}/${s})...`,(t===1||t%5===0)&&u.warning(`任务 ${e} 运行中,后端服务暂时不可用,正在自动重试`),await ce(K());continue}await ce(K())}}async function Fe(){const e=U.value.trim();if(!e){u.warning("请输入店铺名称");return}Q.value=!0;try{await qt(e),U.value="",await re(),u.success("已加入备选")}catch(t){u.error(t instanceof Error?t.message:"保存失败")}finally{Q.value=!1}}async function ut(e){try{await At(e.id),await re(),p.value=[],x(),u.success("已删除")}catch(t){u.error(t instanceof Error?t.message:"删除失败")}}function it(){const e=new Set,t=U.value.trim();t&&e.add(t);for(const s of fe.value)s?.shop_name?.trim()&&e.add(s.shop_name.trim());return[...e]}function ct(e,t){const s=new Map;for(const r of t){const i=(r.shopName||"").trim();i&&s.set(i,r)}const o=new Set,l=[];for(const r of e){const i=(r.shopName||"").trim();i&&s.has(i)?(l.push(s.get(i)),o.add(i)):l.push(r)}for(const r of t){const i=(r.shopName||"").trim();if(!i){l.push(r);continue}o.has(i)||(l.push(r),o.add(i))}return l}async function dt(){const e=it();if(!e.length){u.warning("请勾选备选店铺,或在输入框中填写店名(可与勾选合并)");return}z.value=!0;try{const s=(await Bt(e)).items||[];p.value=ct(p.value,s),x(),s.length?u.success(`本次匹配 ${s.length} 个店铺名,表格共 ${p.value.length} 条`):u.warning("未返回匹配结果")}catch(t){u.error(t instanceof Error?t.message:"匹配失败")}finally{z.value=!1}}function de(e){const t=e.taskId;return t?Te(t)||e.taskStatus||"":e.taskStatus||""}function Me(e){const t=de(e);return t==="SUCCESS"?"已完成":t==="FAILED"?"失败":t==="RUNNING"?"执行中":e.success?"已完成":"等待中"}function Oe(e){const t=de(e);return t==="SUCCESS"||e.success?"success":t==="FAILED"?"failed":"running"}function Ue(e){return!e.resultId||!e.fileReady&&!e.downloadUrl?!1:de(e)==="SUCCESS"||e.success===!0}async function Le(e){if(!e.resultId)return;const t=xt(e.resultId),s=e.outputFilename||`${e.shopName||"result"}.zip`,o=await jt(t,s,`product-risk:${e.resultId}`);o.success?u.success(`已保存:${o.path||s}`):o.error&&o.error!=="用户取消"&&u.error(o.error)}function ft(e){const t=(e||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[t]||t||"—"}function vt(e){const t=(e.matchMessage||"").trim();return t||(e.matched&&e.matchStatus==="MATCHED"?"紫鸟索引已命中,可推送队列;打开店铺地址由 Python 侧处理":e.matched?"已关联索引,请结合状态列查看是否可推送":"未命中或未就绪,请检查店铺名与索引刷新")}async function pt(){ve.value=!0,await gt()}function ht(){return p.value.find(e=>e.matched)}function yt(){return D.value==="SearchSuppressed"||D.value==="DetailPageRemoved"}async function kt(e){const t=xe();if(!t?.enqueue_json){u.error("当前环境未启用 pywebview enqueue_json");return}const s=await Ne(e),o=s.taskId;g.value={...g.value,[o]:{task:{id:o,status:"RUNNING"},items:s.items}},B(),Ie(o),J(!0);const l={type:"product-risk-resolve-run",ts:Date.now(),data:{taskId:o,items:e,country_codes:[...h.value],risk_listing_filter:D.value}};L.value=JSON.stringify(l,null,2);const r=await t.enqueue_json(l);if(!r?.success)throw R(o),new Error("任务 "+o+" 推送失败:"+(r?.error||"未知错误"));F(e),y.value="任务 "+o+" 已入队,共 "+e.length+" 个店铺,等待执行完成...";const i=await $e(o);if(y.value="任务 "+o+(i==="SUCCESS"?" 已完成":" 执行失败"),i!=="SUCCESS")throw new Error(y.value)}async function gt(){if(b||se.value)return;if(!p.value.length){u.warning("请先匹配店铺");return}const e=xe();if(!e?.enqueue_json){u.error("当前环境未启用 pywebview enqueue_json");return}const t=p.value.filter(l=>l.matched);if(!t.length){u.warning("没有已匹配的店铺可推送");return}se.value=!0,G.value=!0,L.value="";let s=0,o=0;try{if(yt()){await kt(t),u.success("店铺推送已完成:成功 "+t.length+" 条,失败 0 条"),await T(),J(!0);return}let l=0;for(;!b&&ve.value;){const r=ht();if(!r)break;l+=1;try{const i=await Ne([r]),a=i.taskId;g.value={...g.value,[a]:{task:{id:a,status:"RUNNING"},items:i.items}},B(),Ie(a),J(!0);const w={type:"product-risk-resolve-run",ts:Date.now(),data:{taskId:a,items:[r],country_codes:[...h.value],risk_listing_filter:D.value}};L.value=JSON.stringify(w,null,2);const Y=await e.enqueue_json(w);if(!Y?.success){R(a),o+=1,y.value="第 "+l+" 条推送失败:"+(Y?.error||"未知错误")+",已自动继续下一条",u.error(y.value),F([r]);continue}if(F([r]),y.value="任务 "+a+" 已入队,等待执行完成...",await $e(a)!=="SUCCESS"){o+=1,y.value="任务 "+a+" 执行失败,已自动继续下一条",u.error(y.value);continue}s+=1,y.value="任务 "+a+" 已完成"}catch(i){if(b)break;o+=1,y.value="第 "+l+" 条任务处理失败,已自动继续下一条:"+(i instanceof Error?i.message:"未知错误"),u.error(y.value),F([r]);continue}}(s>0||o>0)&&u.success("店铺推送已完成:成功 "+s+" 条,失败 "+o+" 条"),await T(),J(!0)}catch(l){if(b)return;y.value=l instanceof Error?l.message:"推送异常",u.error(y.value)}finally{se.value=!1,G.value=!1}}return wt(()=>{st(),Xe(),Ye(),Ze(),re().catch(()=>{}),We().catch(()=>{}),T().then(()=>(V(),Re())).catch(()=>{}),I().catch(()=>{}),k.value.length&&J(!0)}),_t(()=>{b=!0,rt(),lt(),C.clearScope(),$&&C.clearTimer("preference-save",$)}),(e,t)=>{const s=Ct,o=It,l=Tt,r=Pt,i=Nt;return c(),d("div",Wt,[m(bt,{active:"product-risk"}),n("div",Xt,[n("aside",Yt,[t[7]||(t[7]=n("div",{class:"section-title"},"店铺名称",-1)),n("div",Zt,[t[3]||(t[3]=n("div",{class:"hint"},"输入店铺名后点「确认」加入下方备选区(按当前登录用户保存)。仅索引可命中的店铺可入库。勾选备选后点「匹配店铺」,再「推送到 Python 队列」。",-1)),n("div",es,[m(s,{modelValue:U.value,"onUpdate:modelValue":t[0]||(t[0]=a=>U.value=a),clearable:"",placeholder:"请输入店铺名称",onKeyup:St(Fe,["enter"])},null,8,["modelValue"]),n("button",{type:"button",class:"opt-btn",disabled:Q.value,onClick:Fe},f(Q.value?"保存中…":"确认"),9,ts)])]),t[8]||(t[8]=n("div",{class:"section-title"},"备选区域",-1)),te.value.length?(c(),d("div",as,[m(l,{data:te.value,"row-key":"id",height:"240",class:"candidate-table",onSelectionChange:at},{default:E(()=>[m(o,{type:"selection",width:"42"}),m(o,{prop:"shop_name",label:"店铺名","min-width":"120","show-overflow-tooltip":""}),m(o,{label:"操作",width:"72",align:"center"},{default:E(({row:a})=>[n("button",{type:"button",class:"link-danger",onClick:w=>ut(a)},"删除",8,ns)]),_:1})]),_:1},8,["data"])])):(c(),d("div",ss,"暂无备选店铺,请先输入并确认")),t[9]||(t[9]=n("div",{class:"section-title"},"处理国家与顺序",-1)),t[10]||(t[10]=n("p",{class:"hint country-pref-hint"},[M(" 勾选需要处理的站点(可只选 2~3 国);上方勾选区"),n("strong",null,"先按已选顺序"),M("排列,其余未选国家排在后面。拖拽下方列表调整顺序后会与上方同步。设置会按当前登录用户保存。 ")],-1)),n("div",os,[(c(!0),d(O,null,H(je.value,a=>(c(),d("label",{key:a.code,class:"country-check-row"},[n("input",{type:"checkbox",class:"country-check-input",checked:Ve(a.code),disabled:ye(a.code),onChange:w=>Ke(a.code,w)},null,40,ls),n("span",rs,f(a.label)+"("+f(a.code)+")",1)]))),128))]),h.value.length?(c(),d("div",us,[t[5]||(t[5]=n("div",{class:"country-order-caption"},"已选顺序(拖拽 ⋮⋮ 调整)",-1)),n("div",is,[(c(!0),d(O,null,H(h.value,(a,w)=>(c(),d("div",{key:a,class:Z(["country-drag-row",{dragging:q.value===w}]),draggable:"true",onDragstart:Y=>He(w),onDragend:Qe,onDragover:t[1]||(t[1]=qe(()=>{},["prevent"])),onDrop:qe(Y=>ze(w),["prevent"])},[t[4]||(t[4]=n("span",{class:"drag-handle",title:"拖动排序"},"⋮⋮",-1)),n("span",ds,f(he(a))+"("+f(a)+")",1)],42,cs))),128))])])):_("",!0),ae.value?(c(),d("div",fs,"保存中…")):_("",!0),t[11]||(t[11]=n("div",{class:"section-title"},"商品列表筛选",-1)),t[12]||(t[12]=n("p",{class:"hint listing-filter-hint"},"与「推送到 Python 队列」一并下发,供 Python 区分处理场景。",-1)),n("div",vs,[m(i,{modelValue:D.value,"onUpdate:modelValue":t[2]||(t[2]=a=>D.value=a),class:"listing-filter-select",teleported:"",placeholder:"选择筛选类型"},{default:E(()=>[(c(!0),d(O,null,H(Et(zt),a=>(c(),Ae(r,{key:a.value,label:a.label,value:a.value},null,8,["label","value"]))),128))]),_:1},8,["modelValue"])]),n("div",ps,[n("button",{type:"button",class:"btn-run",disabled:z.value,onClick:dt},f(z.value?"匹配中…":"匹配店铺"),9,hs),n("button",{type:"button",class:"btn-run btn-queue",disabled:G.value||!p.value.length,onClick:pt},f(G.value?"推送中…":"推送到 Python 队列"),9,ys)]),t[13]||(t[13]=n("p",{class:"loading-msg"},[M("在搜索结果中禁止显示、详情页面已删除会把匹配店铺合并为一个任务入队,避免同时打开多个紫鸟窗口;其它筛选仍按店铺逐条入队。Python 每处理完一店可 POST "),n("code",null,"/api/product-risk-resolve/tasks/{taskId}/result"),M("(可多次,每次可只含已完成的店铺);全部完成后任务结束。前端轮询任务状态。 ")],-1)),y.value?(c(),d("div",ks,[t[6]||(t[6]=n("div",{class:"section-title queue-debug-title"},"推送结果",-1)),n("div",gs,f(y.value),1),L.value?(c(),d("pre",ms,f(L.value),1)):_("",!0)])):_("",!0)]),n("section",ws,[t[22]||(t[22]=n("div",{class:"panel-header"},"匹配与任务",-1)),n("div",_s,[n("div",bs,[n("div",Ss,[t[14]||(t[14]=n("span",{class:"summary-label"},"备选店铺数",-1)),n("strong",null,f(A.value.candidateCount),1)]),n("div",Cs,[t[15]||(t[15]=n("span",{class:"summary-label"},"已结束任务",-1)),n("strong",null,f(A.value.processedTaskCount),1)]),n("div",Is,[t[16]||(t[16]=n("span",{class:"summary-label"},"成功任务",-1)),n("strong",null,f(A.value.successTaskCount),1)]),n("div",Ts,[t[17]||(t[17]=n("span",{class:"summary-label"},"失败任务",-1)),n("strong",null,f(A.value.failedTaskCount),1)])]),t[21]||(t[21]=n("div",{class:"subsection-title"},"匹配结果",-1)),p.value.length?(c(),Ae(l,{key:1,data:p.value,"row-key":j,"highlight-current-row":!1,class:"result-table match-table"},{default:E(()=>[m(o,{prop:"shopName",label:"店铺名","min-width":"100"}),m(o,{label:"匹配",width:"72",align:"center"},{default:E(({row:a})=>[n("span",{class:Z(a.matched?"ok":"fail")},f(a.matched?"是":"否"),3)]),_:1}),m(o,{prop:"shopId",label:"店铺ID","min-width":"120","show-overflow-tooltip":""}),m(o,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),m(o,{prop:"companyName",label:"公司","min-width":"100","show-overflow-tooltip":""}),m(o,{label:"状态",width:"100","show-overflow-tooltip":""},{default:E(({row:a})=>[M(f(ft(a.matchStatus)),1)]),_:1}),m(o,{label:"说明","min-width":"140","show-overflow-tooltip":""},{default:E(({row:a})=>[M(f(vt(a)),1)]),_:1}),m(o,{label:"操作",width:"72",align:"center"},{default:E(({row:a})=>[n("button",{type:"button",class:"link-danger",onClick:w=>tt(a)},"删除",8,Ps)]),_:1})]),_:1},8,["data"])):(c(),d("div",Es,"完成「匹配店铺」后,在此展示紫鸟索引匹配结果,供核对后再推送队列。")),n("div",Ns,[t[20]||(t[20]=n("div",{class:"result-list-header"},[n("span",null,"处理记录")],-1)),nt.value?(c(),d(O,{key:1},[ue.value.length?(c(),d("div",Ds,[t[18]||(t[18]=n("div",{class:"result-subsection-title"},"当前任务",-1)),n("ul",$s,[(c(!0),d(O,null,H(ue.value,a=>(c(),d("li",{key:`cur-${a.resultId}-${a.taskId}`,class:"task-item split-result-item"},[n("div",Fs,[n("span",{class:"id",title:a.shopName||""},f(a.shopName||"-"),9,Ms),n("div",Os,"任务 ID:"+f(a.taskId??"-"),1),a.platform?(c(),d("div",Us,"平台:"+f(a.platform),1)):_("",!0),a.error?(c(),d("div",Ls,"错误:"+f(a.error),1)):_("",!0)]),n("div",qs,[n("span",{class:Z(["status",Oe(a)])},f(Me(a)),3),Ue(a)?(c(),d("button",{key:0,type:"button",class:"download",onClick:w=>Le(a)}," 下载 ",8,As)):_("",!0),n("button",{type:"button",class:"btn-delete",onClick:w=>Se(a)},"删除",8,Bs)])]))),128))])])):_("",!0),ie.value.length?(c(),d("div",xs,[t[19]||(t[19]=n("div",{class:"result-subsection-title"},"历史记录",-1)),n("ul",js,[(c(!0),d(O,null,H(ie.value,a=>(c(),d("li",{key:`his-${a.resultId}-${a.taskId}`,class:"task-item split-result-item"},[n("div",Vs,[n("span",{class:"id",title:a.shopName||""},f(a.shopName||"-"),9,Ks),n("div",Js,"任务 ID:"+f(a.taskId??"-"),1),a.outputFilename?(c(),d("div",Hs,"文件:"+f(a.outputFilename),1)):_("",!0),a.error?(c(),d("div",Qs,"错误:"+f(a.error),1)):_("",!0)]),n("div",zs,[n("span",{class:Z(["status",Oe(a)])},f(Me(a)),3),Ue(a)?(c(),d("button",{key:0,type:"button",class:"download",onClick:w=>Le(a)}," 下载 ",8,Gs)):_("",!0),n("button",{type:"button",class:"btn-delete",onClick:w=>Se(a)},"删除",8,Ws)])]))),128))])])):_("",!0)],64)):(c(),d("div",Rs,"暂无处理记录。推送队列并等待 Python 回传后,将在此显示下载链接。"))])])])])])}}}),Ys=Jt(Xs,[["__scopeId","data-v-7520aec4"]]);Ht(Ys).use(Qt).mount("#app"); diff --git a/app/assets/query-asin.js b/app/assets/query-asin.js index 671dc12..b18cefe 100644 --- a/app/assets/query-asin.js +++ b/app/assets/query-asin.js @@ -1 +1 @@ -import{d as nt,o as ot,M as lt,a as u,c as i,b as v,B as rt,e as o,ad as ut,ae as it,t as r,af as S,ag as ct,ah as dt,f as p,ak as ft,n as re,y as $e,F as ue,r as Ee,g as d,h as q,bo as ht,bp as vt,bq as pt,E as f,br as yt,bs as mt,bt as gt,i as wt,bu as _t,bv as kt,bw as It,s as bt,bx as St,by as Tt,V as X,bz as Ct,_ as At,aQ as Nt,q as $t,u as Et}from"./java-modules-DzYrjxib.js";import{z as qt}from"./zh-cn-z8KAT-CE.js";/* empty css */import{c as Qt}from"./categorized-timers-JPA-olTr.js";const Dt={class:"page-shell module-page"},Mt={class:"main-content"},Pt={class:"left-panel"},Ft={class:"input-zone"},Rt={class:"input-row"},Ot=["disabled"],Bt={key:0,class:"empty-candidates"},xt={key:1,class:"candidate-table-scroll"},Lt=["onClick"],Ut={class:"run-row"},Ht=["disabled"],Vt=["disabled"],zt={key:2,class:"queue-debug-card"},jt={class:"queue-debug-line"},Jt={key:0,class:"queue-debug-payload"},Kt={class:"right-panel"},Wt={class:"task-list-wrap"},Xt={class:"clean-result-summary"},Gt={class:"summary-card"},Yt={class:"summary-card"},Zt={class:"summary-card"},es={class:"summary-card"},ts={key:0,class:"empty-tasks narrow"},ss=["onClick"],as={class:"result-list-wrap"},ns={key:0,class:"empty-tasks"},os={key:0,class:"result-subsection"},ls={class:"task-list"},rs={class:"left split-result-main"},us=["title"],is={class:"files"},cs={key:0,class:"files"},ds={key:1,class:"files"},fs={key:2,class:"files"},hs={class:"files"},vs={class:"files"},ps={class:"files"},ys={key:3,class:"files"},ms={class:"task-right"},gs=["onClick"],ws={key:1,class:"result-subsection"},_s={class:"task-list"},ks={class:"left split-result-main"},Is=["title"],bs={class:"files"},Ss={key:0,class:"files"},Ts={key:1,class:"files"},Cs={key:2,class:"files"},As={class:"files"},Ns={class:"files"},$s={key:3,class:"files"},Es={class:"files"},qs={key:4,class:"files"},Qs={class:"task-right"},Ds=["onClick"],Ms=["onClick"],qe=30,Ps=nt({__name:"BrandQueryAsinTab",setup(Rs){const O=d(""),G=d([]),B=d([]),m=d([]),k=d([]),Q=d({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),x=d(!1),L=d(!1),Y=d(!1),y=d(""),Z=d(""),h=d([]),c=d(null),T=d(null),C=d(!1),ee=d(!1),w=d({});let A=null;const N=Qt("query-asin"),ie=q(()=>m.value.filter(e=>e.matched&&(e.queryAsins||[]).some(t=>t.asins?.length))),U=q(()=>k.value.filter(e=>!ge(e.taskStatus))),te=q(()=>k.value.filter(e=>ge(e.taskStatus))),se=q(()=>!!c.value||h.value.length>0),H=q(()=>C.value||se.value),ce=q(()=>C.value&&se.value);function V(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function de(){return`query-asin:matched:${V()}`}function fe(){return`query-asin:queue-state:${V()}`}function ae(){return`query-asin:start-times:${V()}`}function b(e){return`${(e.shopName||"").trim()}::${e.shopId||""}`}function z(e){return`${e.taskId??0}:${e.resultId??0}`}let _=!1;function he(e){return _?Promise.resolve():N.sleep("queue-wait",e)}function Qe(){N.clearCategory("queue-wait")}function ve(e){const t=e instanceof Error?e.message.toLowerCase():String(e||"").toLowerCase();return t.includes("network error")||t.includes("failed to fetch")||t.includes("timeout")||t.includes("503")||t.includes("502")||t.includes("504")||t.includes("500")||t.includes("load failed")}async function De(e,t,n=20){let a=0;for(;;){if(_)throw new Error("component disposed");try{return await e()}catch(l){if(!ve(l)||a>=n-1)throw l;a+=1,t?.(a,n),await he(X())}}}function pe(e,t){return`query-asin:${e}:${t||"shop"}:${Date.now()}`}function D(e){if(!e)return"-";const t=new Date(e);if(Number.isNaN(t.getTime()))return e;const n=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),l=String(t.getDate()).padStart(2,"0"),s=String(t.getHours()).padStart(2,"0"),g=String(t.getMinutes()).padStart(2,"0"),le=String(t.getSeconds()).padStart(2,"0");return`${n}-${a}-${l} ${s}:${g}:${le}`}function Me(e){const t=(e||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[t]||t||"-"}function Pe(e){const t=(e.matchMessage||"").trim();return t||(e.matched&&e.matchStatus==="MATCHED"?"索引已命中,可推送到 Python 队列":e.matched?"已命中索引,请结合状态列确认":"未命中或未就绪,请检查店铺名")}function Fe(e){const t=I(e),n=Math.max(...t.map(a=>a.asins?.length||0),1);return Array.from({length:n},(a,l)=>({shopName:l===0?e.shopName:"",countries:t.map(s=>({country:s.country,asin:s.asins?.[l]||""}))}))}function ye(e){const t=I(e),n=t.reduce((l,s)=>l+(s.asins?.length||0),0);return`${t.filter(l=>l.asins?.length).map(l=>l.country).join("、")||"无国家"},共 ${n} 个 ASIN`}function j(e){return(e||[]).map(t=>({country:(t.country||"").trim().toUpperCase(),asins:Array.from(new Set((t.asins||[]).map(n=>(n||"").trim().toUpperCase()).filter(Boolean)))})).filter(t=>t.country&&t.asins.length)}function I(e){return j(e?.queryAsins?.length?e.queryAsins:e?.query_asins)}function J(e){return I(e).some(t=>t.asins.length)}function me(e){const t=(e||"").trim(),n=[T.value,...h.value,...m.value],a=n.find(s=>(s?.shopName||"").trim()===t&&J(s)),l=n.find(s=>J(s));return I(a||l)}function $(e,t){const n=J(e)?I(e):I(t||void 0);return{...e,queryAsins:n.length?n:me(e.shopName)}}function ge(e){return e==="SUCCESS"||e==="FAILED"||e==="COMPLETED"}function we(e){return e==="SUCCESS"||e==="COMPLETED"?"已完成":e==="FAILED"?"失败":"执行中"}function _e(e){return e==="SUCCESS"||e==="COMPLETED"?"success":e==="FAILED"?"failed":"running"}function Re(e){return!!(e.resultId&&(e.fileReady||e.downloadUrl))}function ke(){typeof window>"u"||window.localStorage.setItem(de(),JSON.stringify(m.value))}function Oe(){try{const e=typeof window<"u"?window.localStorage.getItem(de()):null;m.value=e?JSON.parse(e):[]}catch{m.value=[]}}function E(){if(typeof window>"u")return;const e={pendingQueue:h.value,activeTaskId:c.value,activeQueueItem:T.value};window.localStorage.setItem(fe(),JSON.stringify(e))}function Ie(){if(!(typeof window>"u")){if(!Object.keys(w.value).length){window.localStorage.removeItem(ae());return}window.localStorage.setItem(ae(),JSON.stringify(w.value))}}function Be(){try{const e=typeof window<"u"?window.localStorage.getItem(fe()):null;if(!e)return;const t=JSON.parse(e);h.value=t.pendingQueue||[],c.value=t.activeTaskId??null,T.value=t.activeQueueItem??null}catch{h.value=[],c.value=null,T.value=null}}function xe(){try{const e=typeof window<"u"?window.localStorage.getItem(ae()):null,t=e?JSON.parse(e):{},n={};for(const[a,l]of Object.entries(t||{})){const s=Number(a);!Number.isFinite(s)||s<=0||typeof l!="string"||!l.trim()||(n[s]=l)}w.value=n}catch{w.value={}}}function Le(e,t=new Date().toISOString()){!Number.isFinite(e)||e<=0||(w.value={...w.value,[e]:t},Ie())}function ne(e){if(!e||!(e in w.value))return;const t={...w.value};delete t[e],w.value=t,Ie()}function be(e){return e&&w.value[e]||""}function M(){c.value=null,T.value=null,E()}function P(){se.value||(C.value=!1,Y.value=!1,ee.value=!1,W(),E())}function Ue(e){const t=e instanceof Error?e.message:String(e||"");return/记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(t)}function He(e){k.value=k.value.filter(t=>!(e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId))}function Ve(e,t){const n=new Map;for(const a of e)n.set(b(a),a);for(const a of t)n.set(b(a),a);return Array.from(n.values())}async function F(){G.value=await ht()}async function K(){Q.value=await vt()}async function oe(){const e=await pt();k.value=(e.items||[]).map(t=>$(t))}async function R(){await Promise.all([K(),oe()])}function Se(){if(!c.value){P();return}if(k.value.some(n=>n.taskId===c.value))return;const t=c.value;M(),y.value=h.value.length?`任务 ${t} 已不存在,已跳过并继续剩余队列`:"当前任务已不存在,已释放本地队列状态",P()}function ze(e){if(!e.length)return;const t=new Map(e.map(a=>[z(a),$(a)])),n=k.value.map(a=>{const l=t.get(z(a));if(!l)return $(a);const s=J(l)?I(l):I(a).length?I(a):me(l.shopName||a.shopName);return{...a,...l,queryAsins:s}});for(const a of e){const l=z(a);n.some(s=>z(s)===l)||n.push($(a))}k.value=n}async function Te(e){const t=Array.from(new Set((e&&e.length?e:U.value.map(a=>a.taskId??0)).filter(a=>Number.isFinite(a)&&a>0)));if(!t.length)return;const n=await Ct(t);ze(n.items||[]),(n.missingTaskIds||[]).length&&(await oe(),Se())}function je(){if(W(),_||!H.value)return;const e=async()=>{A=null,!(_||!H.value)&&(await Te(),!_&&H.value&&(A=N.setTimeout("history-poll",e,X()*2)))};A=N.setTimeout("history-poll",e,X()*2)}function W(){A&&(N.clearTimer("history-poll",A),A=null)}function Je(e){B.value=e}async function Ce(){const e=O.value.trim();if(!e){f.warning("请输入店铺名");return}x.value=!0;try{await yt(e),O.value="",await Promise.all([F(),K()]),f.success("已加入备选区")}catch(t){f.error(t instanceof Error?t.message:"添加失败")}finally{x.value=!1}}async function Ke(e){try{await mt(e),B.value=B.value.filter(t=>t.id!==e),await Promise.all([F(),K()]),f.success("已删除")}catch(t){f.error(t instanceof Error?t.message:"删除失败")}}function We(e,t){const n=new Map;for(const a of e)n.set(b(a),a);for(const a of t)n.set(b(a),a);return Array.from(n.values())}async function Xe(){const e=B.value.map(t=>t.shop_name).filter(Boolean);if(!e.length){f.warning("请先勾选备选区店铺");return}L.value=!0;try{const t=await gt(e);m.value=We(m.value,t.items||[]),ke(),f.success(`本次返回 ${t.items?.length||0} 条匹配结果`)}catch(t){f.error(t instanceof Error?t.message:"匹配失败")}finally{L.value=!1}}function Ge(e){if(H.value){f.warning("队列执行中,请等待当前串行任务结束后再调整");return}m.value=m.value.filter(t=>b(t)!==b(e)),ke()}function Ye(e){return{shopName:e.shopName,matched:e.matched,shopId:e.shopId,platform:e.platform,companyName:e.companyName,matchStatus:e.matchStatus,matchMessage:e.matchMessage,queryAsins:j(e.queryAsins)}}function Ze(e,t){const n=pe(e,t.shopName);return{type:"query-asin-run",ts:Date.now(),data:{taskId:e,user_id:Number(V())||0,source:"frontend-vue-query-asin",submissionId:n,items:[{shopName:t.shopName,submissionId:n,shopId:t.shopId,platform:t.platform,companyName:t.companyName,matched:t.matched,matchStatus:t.matchStatus,matchMessage:t.matchMessage,queryAsins:j(t.queryAsins)}],query_asins:j(t.queryAsins),query_asin_rows:Fe(t)}}}function et(e){return k.value.find(t=>t.taskId===e)}async function tt(e){let t=0;for(;;){if(_)return"STOPPED";try{if(await Te([e]),c.value!==e)return"FAILED";t>0&&(y.value=`任务 ${e} 后端已恢复,继续等待执行结果...`),t=0;const a=et(e)?.taskStatus||"";if(a==="SUCCESS"||a==="FAILED"||a==="COMPLETED")return a}catch(n){if(!ve(n))throw n;if(t+=1,t>=qe)throw new Error(`任务 ${e} 等待后端恢复超时,请稍后刷新查看状态`);y.value=`任务 ${e} 执行中,正在等待后端服务恢复(${t}/${qe})...`}await he(X())}}async function Ae(){if(!(_||C.value)){C.value=!0,Y.value=!0,je();try{const e=wt();if(!e?.enqueue_json)throw new Error("当前客户端未提供 enqueue_json");for(;!_&&(c.value||h.value.length);){if(c.value){const g=await tt(c.value);y.value=h.value.length>0?`任务 ${c.value} ${g==="SUCCESS"?"已完成":"执行失败"},自动继续下一个(剩余 ${h.value.length} 条)`:`任务 ${c.value} ${g==="SUCCESS"?"已完成":"执行失败"}`,M();continue}const t=h.value.shift();if(E(),!t)break;const n=await De(()=>_t([Ye(t)]),(g,le)=>{y.value=`后端服务暂时不可用,正在重试创建任务(${g}/${le})...`}),a=n.items?.[0]?$(n.items[0],t):void 0;if(!a?.taskId||!a.resultId)throw new Error("后端未返回有效任务标识");c.value=n.taskId,T.value=$(t,a),E(),await R();const l=Ze(n.taskId,a);Z.value=JSON.stringify(l,null,2);const s=await e.enqueue_json(l);if(!s?.success){await kt(n.taskId,{shops:[{shopName:a.shopName||t.shopName||"",error:s?.error||`任务 ${n.taskId} 推送失败`,shopDone:!0,submissionId:pe(n.taskId,a.shopName||t.shopName)}]}),await R(),y.value=`任务 ${n.taskId} 推送失败,已自动继续下一个任务`,M();continue}Le(n.taskId),y.value=h.value.length>0?`任务 ${n.taskId} 已入队,等待完成后自动继续下一个(剩余 ${h.value.length} 条)`:`任务 ${n.taskId} 已入队,等待执行完成`}y.value="串行队列已执行完成",await R(),f.success("查询ASIN队列已按顺序执行完成")}catch(e){if(_)return;const t=e instanceof Error?e.message:"队列执行失败";y.value=t,f.error(t),await R()}finally{C.value=!1,Y.value=!1,W(),E()}}}async function st(){ee.value=!0,P();const e=ie.value;if(!e.length){f.warning("请先匹配可用店铺");return}h.value=Ve(h.value,e),E(),y.value=`已加入 ${e.length} 条店铺,开始串行执行`,await Ae()}async function at(e){if(!e.resultId)return;const t=It(e.resultId),n=e.outputFilename||`${e.shopName||"result"}.xlsx`,a=await bt(t,n,`query-asin:${e.resultId}`);a.success?f.success(`已保存: ${a.path||n}`):a.error&&a.error!=="用户取消"&&f.error(a.error)}async function Ne(e){try{if(e.taskId)await St(e.taskId),c.value===e.taskId&&M(),ne(e.taskId);else if(e.resultId)await Tt(e.resultId),ne(e.taskId);else throw new Error("缺少可删除的任务标识");await Promise.all([F(),R()]),P(),f.success("已删除")}catch(t){if(Ue(t)){e.taskId&&c.value===e.taskId&&M(),ne(e.taskId),He(e),await F(),P(),f.success("后端记录已不存在,已同步移除本地记录");return}f.error(t instanceof Error?t.message:"删除失败")}}return ot(async()=>{Oe(),Be(),xe(),await Promise.all([F(),K(),oe()]),Se(),(c.value||h.value.length)&&(ee.value=!0,y.value=c.value!=null?`检测到未完成队列,继续等待任务 ${c.value} 完成并自动接续后续店铺`:`检测到未完成队列,继续执行剩余 ${h.value.length} 条店铺`,Ae())}),lt(()=>{_=!0,W(),Qe(),N.clearScope()}),(e,t)=>{const n=it,a=ct,l=dt;return u(),i("div",Dt,[v(rt,{active:"query-asin"}),o("div",Mt,[o("aside",Pt,[t[3]||(t[3]=o("div",{class:"section-title"},"店铺输入",-1)),o("div",Ft,[t[1]||(t[1]=o("div",{class:"hint"}," 左侧负责录入店铺并加入备选区,确认命中后推送到 Python 队列。查询ASIN按店铺串行执行:上一个任务完成后会自动开始下一个,失败也会继续下一个。 ",-1)),o("div",Rt,[v(n,{modelValue:O.value,"onUpdate:modelValue":t[0]||(t[0]=s=>O.value=s),clearable:"",placeholder:"请输入店铺名后回车或点击添加",onKeyup:ut(Ce,["enter"])},null,8,["modelValue"]),o("button",{type:"button",class:"opt-btn",disabled:x.value,onClick:Ce},r(x.value?"添加中...":"添加"),9,Ot)])]),t[4]||(t[4]=o("div",{class:"section-title"},"备选区",-1)),G.value.length?(u(),i("div",xt,[v(l,{data:G.value,"row-key":"id",height:"260",class:"candidate-table",onSelectionChange:Je},{default:S(()=>[v(a,{type:"selection",width:"42"}),v(a,{prop:"shop_name",label:"店铺名","min-width":"140","show-overflow-tooltip":""}),v(a,{label:"操作",width:"72",align:"center"},{default:S(({row:s})=>[o("button",{type:"button",class:"link-danger",onClick:g=>Ke(s.id)}," 删除 ",8,Lt)]),_:1})]),_:1},8,["data"])])):(u(),i("div",Bt," 暂无备选店铺,请先输入并添加 ")),o("div",Ut,[o("button",{type:"button",class:"btn-run",disabled:L.value,onClick:Xe},r(L.value?"匹配中...":"匹配店铺"),9,Ht),o("button",{type:"button",class:"btn-run btn-queue",disabled:ce.value||!ie.value.length,onClick:st},r(ce.value?"串行执行中...":"推送到 Python 队列"),9,Vt)]),t[5]||(t[5]=o("p",{class:"loading-msg"}," 当前页面会按店铺串行推送任务,并在任务成功或失败后自动接续下一个任务。服务端临时重启时会自动重试查询状态,恢复后继续后续店铺。 ",-1)),y.value?(u(),i("div",zt,[t[2]||(t[2]=o("div",{class:"section-title queue-debug-title"},"队列状态",-1)),o("div",jt,r(y.value),1),Z.value?(u(),i("pre",Jt,r(Z.value),1)):p("",!0)])):p("",!0)]),o("section",Kt,[t[14]||(t[14]=o("div",{class:"panel-header"},"匹配与任务",-1)),o("div",Wt,[o("div",Xt,[o("div",Gt,[t[6]||(t[6]=o("span",{class:"summary-label"},"备选店铺",-1)),o("strong",null,r(Q.value.candidateCount),1)]),o("div",Yt,[t[7]||(t[7]=o("span",{class:"summary-label"},"已处理任务",-1)),o("strong",null,r(Q.value.processedTaskCount),1)]),o("div",Zt,[t[8]||(t[8]=o("span",{class:"summary-label"},"成功任务",-1)),o("strong",null,r(Q.value.successTaskCount),1)]),o("div",es,[t[9]||(t[9]=o("span",{class:"summary-label"},"失败任务",-1)),o("strong",null,r(Q.value.failedTaskCount),1)])]),t[13]||(t[13]=o("div",{class:"subsection-title"},"匹配结果",-1)),m.value.length?(u(),ft(l,{key:1,data:m.value,"row-key":b,"highlight-current-row":!1,class:"result-table match-table"},{default:S(()=>[v(a,{prop:"shopName",label:"店铺名","min-width":"120"}),v(a,{label:"匹配",width:"72",align:"center"},{default:S(({row:s})=>[o("span",{class:re(s.matched?"ok":"fail")},r(s.matched?"是":"否"),3)]),_:1}),v(a,{prop:"shopId",label:"店铺 ID","min-width":"120","show-overflow-tooltip":""}),v(a,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),v(a,{prop:"companyName",label:"公司","min-width":"120","show-overflow-tooltip":""}),v(a,{label:"状态",width:"110","show-overflow-tooltip":""},{default:S(({row:s})=>[$e(r(Me(s.matchStatus)),1)]),_:1}),v(a,{label:"说明","min-width":"180","show-overflow-tooltip":""},{default:S(({row:s})=>[$e(r(Pe(s)),1)]),_:1}),v(a,{label:"操作",width:"72",align:"center"},{default:S(({row:s})=>[o("button",{type:"button",class:"link-danger",onClick:g=>Ge(s)}," 删除 ",8,ss)]),_:1})]),_:1},8,["data"])):(u(),i("div",ts," 完成“匹配店铺”后,这里会展示匹配结果。 ")),o("div",as,[t[12]||(t[12]=o("div",{class:"result-list-header"},[o("span",null,"任务记录")],-1)),!U.value.length&&!te.value.length?(u(),i("div",ns," 暂无任务记录。推送到 Python 队列后,这里会展示当前任务和历史任务。 ")):(u(),i(ue,{key:1},[U.value.length?(u(),i("div",os,[t[10]||(t[10]=o("div",{class:"result-subsection-title"},"当前任务",-1)),o("ul",ls,[(u(!0),i(ue,null,Ee(U.value,s=>(u(),i("li",{key:`${s.resultId}-${s.taskId}`,class:"task-item"},[o("div",rs,[o("span",{class:"id",title:s.shopName||""},r(s.shopName||"-"),9,us),o("div",is,"任务 ID: "+r(s.taskId??"-"),1),s.resultId?(u(),i("div",cs," 结果 ID: "+r(s.resultId),1)):p("",!0),s.shopId?(u(),i("div",ds," 店铺 ID: "+r(s.shopId),1)):p("",!0),s.platform?(u(),i("div",fs," 平台: "+r(s.platform),1)):p("",!0),o("div",hs," 开始时间: "+r(D(be(s.taskId))),1),o("div",vs," 创建时间: "+r(D(s.createdAt)),1),o("div",ps," ASIN结构: "+r(ye(s)),1),s.error?(u(),i("div",ys," 错误: "+r(s.error),1)):p("",!0)]),o("div",ms,[o("span",{class:re(["status",_e(s.taskStatus)])},r(we(s.taskStatus)),3),o("button",{type:"button",class:"btn-delete",onClick:g=>Ne(s)}," 删除 ",8,gs)])]))),128))])])):p("",!0),te.value.length?(u(),i("div",ws,[t[11]||(t[11]=o("div",{class:"result-subsection-title"},"历史任务",-1)),o("ul",_s,[(u(!0),i(ue,null,Ee(te.value,s=>(u(),i("li",{key:`${s.resultId}-${s.taskId}`,class:"task-item"},[o("div",ks,[o("span",{class:"id",title:s.shopName||""},r(s.shopName||"-"),9,Is),o("div",bs,"任务 ID: "+r(s.taskId??"-"),1),s.resultId?(u(),i("div",Ss," 结果 ID: "+r(s.resultId),1)):p("",!0),s.shopId?(u(),i("div",Ts," 店铺 ID: "+r(s.shopId),1)):p("",!0),s.platform?(u(),i("div",Cs," 平台: "+r(s.platform),1)):p("",!0),o("div",As," 开始时间: "+r(D(be(s.taskId))),1),o("div",Ns," 创建时间: "+r(D(s.createdAt)),1),s.finishedAt?(u(),i("div",$s," 完成时间: "+r(D(s.finishedAt)),1)):p("",!0),o("div",Es," ASIN结构: "+r(ye(s)),1),s.error?(u(),i("div",qs," 错误: "+r(s.error),1)):p("",!0)]),o("div",Qs,[o("span",{class:re(["status",_e(s.taskStatus)])},r(we(s.taskStatus)),3),Re(s)?(u(),i("button",{key:0,type:"button",class:"archive",onClick:g=>at(s)}," 下载结果 ",8,Ds)):p("",!0),o("button",{type:"button",class:"btn-delete",onClick:g=>Ne(s)}," 删除 ",8,Ms)])]))),128))])])):p("",!0)],64))])])])])])}}}),Fs=At(Ps,[["__scopeId","data-v-c2e27ea1"]]);Nt.locale("zh-cn");$t(Fs).use(Et,{locale:qt}).mount("#app"); +import{d as nt,o as ot,M as lt,a as u,c as i,b as v,B as rt,e as o,ad as ut,ae as it,t as r,af as S,ag as ct,ah as dt,f as p,ak as ft,n as re,y as $e,F as ue,r as Ee,g as d,h as q,bo as ht,bp as vt,bq as pt,E as f,br as yt,bs as mt,bt as gt,i as wt,bu as _t,bv as kt,bw as It,s as bt,bx as St,by as Tt,V as X,bz as Ct,_ as At,aQ as Nt,q as $t,u as Et}from"./java-modules-B8c-YG5x.js";import{z as qt}from"./zh-cn-CscLo6na.js";/* empty css */import{c as Qt}from"./categorized-timers-JPA-olTr.js";const Dt={class:"page-shell module-page"},Mt={class:"main-content"},Pt={class:"left-panel"},Ft={class:"input-zone"},Rt={class:"input-row"},Ot=["disabled"],Bt={key:0,class:"empty-candidates"},xt={key:1,class:"candidate-table-scroll"},Lt=["onClick"],Ut={class:"run-row"},Ht=["disabled"],Vt=["disabled"],zt={key:2,class:"queue-debug-card"},jt={class:"queue-debug-line"},Jt={key:0,class:"queue-debug-payload"},Kt={class:"right-panel"},Wt={class:"task-list-wrap"},Xt={class:"clean-result-summary"},Gt={class:"summary-card"},Yt={class:"summary-card"},Zt={class:"summary-card"},es={class:"summary-card"},ts={key:0,class:"empty-tasks narrow"},ss=["onClick"],as={class:"result-list-wrap"},ns={key:0,class:"empty-tasks"},os={key:0,class:"result-subsection"},ls={class:"task-list"},rs={class:"left split-result-main"},us=["title"],is={class:"files"},cs={key:0,class:"files"},ds={key:1,class:"files"},fs={key:2,class:"files"},hs={class:"files"},vs={class:"files"},ps={class:"files"},ys={key:3,class:"files"},ms={class:"task-right"},gs=["onClick"],ws={key:1,class:"result-subsection"},_s={class:"task-list"},ks={class:"left split-result-main"},Is=["title"],bs={class:"files"},Ss={key:0,class:"files"},Ts={key:1,class:"files"},Cs={key:2,class:"files"},As={class:"files"},Ns={class:"files"},$s={key:3,class:"files"},Es={class:"files"},qs={key:4,class:"files"},Qs={class:"task-right"},Ds=["onClick"],Ms=["onClick"],qe=30,Ps=nt({__name:"BrandQueryAsinTab",setup(Rs){const O=d(""),G=d([]),B=d([]),m=d([]),k=d([]),Q=d({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),x=d(!1),L=d(!1),Y=d(!1),y=d(""),Z=d(""),h=d([]),c=d(null),T=d(null),C=d(!1),ee=d(!1),w=d({});let A=null;const N=Qt("query-asin"),ie=q(()=>m.value.filter(e=>e.matched&&(e.queryAsins||[]).some(t=>t.asins?.length))),U=q(()=>k.value.filter(e=>!ge(e.taskStatus))),te=q(()=>k.value.filter(e=>ge(e.taskStatus))),se=q(()=>!!c.value||h.value.length>0),H=q(()=>C.value||se.value),ce=q(()=>C.value&&se.value);function V(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function de(){return`query-asin:matched:${V()}`}function fe(){return`query-asin:queue-state:${V()}`}function ae(){return`query-asin:start-times:${V()}`}function b(e){return`${(e.shopName||"").trim()}::${e.shopId||""}`}function z(e){return`${e.taskId??0}:${e.resultId??0}`}let _=!1;function he(e){return _?Promise.resolve():N.sleep("queue-wait",e)}function Qe(){N.clearCategory("queue-wait")}function ve(e){const t=e instanceof Error?e.message.toLowerCase():String(e||"").toLowerCase();return t.includes("network error")||t.includes("failed to fetch")||t.includes("timeout")||t.includes("503")||t.includes("502")||t.includes("504")||t.includes("500")||t.includes("load failed")}async function De(e,t,n=20){let a=0;for(;;){if(_)throw new Error("component disposed");try{return await e()}catch(l){if(!ve(l)||a>=n-1)throw l;a+=1,t?.(a,n),await he(X())}}}function pe(e,t){return`query-asin:${e}:${t||"shop"}:${Date.now()}`}function D(e){if(!e)return"-";const t=new Date(e);if(Number.isNaN(t.getTime()))return e;const n=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),l=String(t.getDate()).padStart(2,"0"),s=String(t.getHours()).padStart(2,"0"),g=String(t.getMinutes()).padStart(2,"0"),le=String(t.getSeconds()).padStart(2,"0");return`${n}-${a}-${l} ${s}:${g}:${le}`}function Me(e){const t=(e||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[t]||t||"-"}function Pe(e){const t=(e.matchMessage||"").trim();return t||(e.matched&&e.matchStatus==="MATCHED"?"索引已命中,可推送到 Python 队列":e.matched?"已命中索引,请结合状态列确认":"未命中或未就绪,请检查店铺名")}function Fe(e){const t=I(e),n=Math.max(...t.map(a=>a.asins?.length||0),1);return Array.from({length:n},(a,l)=>({shopName:l===0?e.shopName:"",countries:t.map(s=>({country:s.country,asin:s.asins?.[l]||""}))}))}function ye(e){const t=I(e),n=t.reduce((l,s)=>l+(s.asins?.length||0),0);return`${t.filter(l=>l.asins?.length).map(l=>l.country).join("、")||"无国家"},共 ${n} 个 ASIN`}function j(e){return(e||[]).map(t=>({country:(t.country||"").trim().toUpperCase(),asins:Array.from(new Set((t.asins||[]).map(n=>(n||"").trim().toUpperCase()).filter(Boolean)))})).filter(t=>t.country&&t.asins.length)}function I(e){return j(e?.queryAsins?.length?e.queryAsins:e?.query_asins)}function J(e){return I(e).some(t=>t.asins.length)}function me(e){const t=(e||"").trim(),n=[T.value,...h.value,...m.value],a=n.find(s=>(s?.shopName||"").trim()===t&&J(s)),l=n.find(s=>J(s));return I(a||l)}function $(e,t){const n=J(e)?I(e):I(t||void 0);return{...e,queryAsins:n.length?n:me(e.shopName)}}function ge(e){return e==="SUCCESS"||e==="FAILED"||e==="COMPLETED"}function we(e){return e==="SUCCESS"||e==="COMPLETED"?"已完成":e==="FAILED"?"失败":"执行中"}function _e(e){return e==="SUCCESS"||e==="COMPLETED"?"success":e==="FAILED"?"failed":"running"}function Re(e){return!!(e.resultId&&(e.fileReady||e.downloadUrl))}function ke(){typeof window>"u"||window.localStorage.setItem(de(),JSON.stringify(m.value))}function Oe(){try{const e=typeof window<"u"?window.localStorage.getItem(de()):null;m.value=e?JSON.parse(e):[]}catch{m.value=[]}}function E(){if(typeof window>"u")return;const e={pendingQueue:h.value,activeTaskId:c.value,activeQueueItem:T.value};window.localStorage.setItem(fe(),JSON.stringify(e))}function Ie(){if(!(typeof window>"u")){if(!Object.keys(w.value).length){window.localStorage.removeItem(ae());return}window.localStorage.setItem(ae(),JSON.stringify(w.value))}}function Be(){try{const e=typeof window<"u"?window.localStorage.getItem(fe()):null;if(!e)return;const t=JSON.parse(e);h.value=t.pendingQueue||[],c.value=t.activeTaskId??null,T.value=t.activeQueueItem??null}catch{h.value=[],c.value=null,T.value=null}}function xe(){try{const e=typeof window<"u"?window.localStorage.getItem(ae()):null,t=e?JSON.parse(e):{},n={};for(const[a,l]of Object.entries(t||{})){const s=Number(a);!Number.isFinite(s)||s<=0||typeof l!="string"||!l.trim()||(n[s]=l)}w.value=n}catch{w.value={}}}function Le(e,t=new Date().toISOString()){!Number.isFinite(e)||e<=0||(w.value={...w.value,[e]:t},Ie())}function ne(e){if(!e||!(e in w.value))return;const t={...w.value};delete t[e],w.value=t,Ie()}function be(e){return e&&w.value[e]||""}function M(){c.value=null,T.value=null,E()}function P(){se.value||(C.value=!1,Y.value=!1,ee.value=!1,W(),E())}function Ue(e){const t=e instanceof Error?e.message:String(e||"");return/记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(t)}function He(e){k.value=k.value.filter(t=>!(e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId))}function Ve(e,t){const n=new Map;for(const a of e)n.set(b(a),a);for(const a of t)n.set(b(a),a);return Array.from(n.values())}async function F(){G.value=await ht()}async function K(){Q.value=await vt()}async function oe(){const e=await pt();k.value=(e.items||[]).map(t=>$(t))}async function R(){await Promise.all([K(),oe()])}function Se(){if(!c.value){P();return}if(k.value.some(n=>n.taskId===c.value))return;const t=c.value;M(),y.value=h.value.length?`任务 ${t} 已不存在,已跳过并继续剩余队列`:"当前任务已不存在,已释放本地队列状态",P()}function ze(e){if(!e.length)return;const t=new Map(e.map(a=>[z(a),$(a)])),n=k.value.map(a=>{const l=t.get(z(a));if(!l)return $(a);const s=J(l)?I(l):I(a).length?I(a):me(l.shopName||a.shopName);return{...a,...l,queryAsins:s}});for(const a of e){const l=z(a);n.some(s=>z(s)===l)||n.push($(a))}k.value=n}async function Te(e){const t=Array.from(new Set((e&&e.length?e:U.value.map(a=>a.taskId??0)).filter(a=>Number.isFinite(a)&&a>0)));if(!t.length)return;const n=await Ct(t);ze(n.items||[]),(n.missingTaskIds||[]).length&&(await oe(),Se())}function je(){if(W(),_||!H.value)return;const e=async()=>{A=null,!(_||!H.value)&&(await Te(),!_&&H.value&&(A=N.setTimeout("history-poll",e,X()*2)))};A=N.setTimeout("history-poll",e,X()*2)}function W(){A&&(N.clearTimer("history-poll",A),A=null)}function Je(e){B.value=e}async function Ce(){const e=O.value.trim();if(!e){f.warning("请输入店铺名");return}x.value=!0;try{await yt(e),O.value="",await Promise.all([F(),K()]),f.success("已加入备选区")}catch(t){f.error(t instanceof Error?t.message:"添加失败")}finally{x.value=!1}}async function Ke(e){try{await mt(e),B.value=B.value.filter(t=>t.id!==e),await Promise.all([F(),K()]),f.success("已删除")}catch(t){f.error(t instanceof Error?t.message:"删除失败")}}function We(e,t){const n=new Map;for(const a of e)n.set(b(a),a);for(const a of t)n.set(b(a),a);return Array.from(n.values())}async function Xe(){const e=B.value.map(t=>t.shop_name).filter(Boolean);if(!e.length){f.warning("请先勾选备选区店铺");return}L.value=!0;try{const t=await gt(e);m.value=We(m.value,t.items||[]),ke(),f.success(`本次返回 ${t.items?.length||0} 条匹配结果`)}catch(t){f.error(t instanceof Error?t.message:"匹配失败")}finally{L.value=!1}}function Ge(e){if(H.value){f.warning("队列执行中,请等待当前串行任务结束后再调整");return}m.value=m.value.filter(t=>b(t)!==b(e)),ke()}function Ye(e){return{shopName:e.shopName,matched:e.matched,shopId:e.shopId,platform:e.platform,companyName:e.companyName,matchStatus:e.matchStatus,matchMessage:e.matchMessage,queryAsins:j(e.queryAsins)}}function Ze(e,t){const n=pe(e,t.shopName);return{type:"query-asin-run",ts:Date.now(),data:{taskId:e,user_id:Number(V())||0,source:"frontend-vue-query-asin",submissionId:n,items:[{shopName:t.shopName,submissionId:n,shopId:t.shopId,platform:t.platform,companyName:t.companyName,matched:t.matched,matchStatus:t.matchStatus,matchMessage:t.matchMessage,queryAsins:j(t.queryAsins)}],query_asins:j(t.queryAsins),query_asin_rows:Fe(t)}}}function et(e){return k.value.find(t=>t.taskId===e)}async function tt(e){let t=0;for(;;){if(_)return"STOPPED";try{if(await Te([e]),c.value!==e)return"FAILED";t>0&&(y.value=`任务 ${e} 后端已恢复,继续等待执行结果...`),t=0;const a=et(e)?.taskStatus||"";if(a==="SUCCESS"||a==="FAILED"||a==="COMPLETED")return a}catch(n){if(!ve(n))throw n;if(t+=1,t>=qe)throw new Error(`任务 ${e} 等待后端恢复超时,请稍后刷新查看状态`);y.value=`任务 ${e} 执行中,正在等待后端服务恢复(${t}/${qe})...`}await he(X())}}async function Ae(){if(!(_||C.value)){C.value=!0,Y.value=!0,je();try{const e=wt();if(!e?.enqueue_json)throw new Error("当前客户端未提供 enqueue_json");for(;!_&&(c.value||h.value.length);){if(c.value){const g=await tt(c.value);y.value=h.value.length>0?`任务 ${c.value} ${g==="SUCCESS"?"已完成":"执行失败"},自动继续下一个(剩余 ${h.value.length} 条)`:`任务 ${c.value} ${g==="SUCCESS"?"已完成":"执行失败"}`,M();continue}const t=h.value.shift();if(E(),!t)break;const n=await De(()=>_t([Ye(t)]),(g,le)=>{y.value=`后端服务暂时不可用,正在重试创建任务(${g}/${le})...`}),a=n.items?.[0]?$(n.items[0],t):void 0;if(!a?.taskId||!a.resultId)throw new Error("后端未返回有效任务标识");c.value=n.taskId,T.value=$(t,a),E(),await R();const l=Ze(n.taskId,a);Z.value=JSON.stringify(l,null,2);const s=await e.enqueue_json(l);if(!s?.success){await kt(n.taskId,{shops:[{shopName:a.shopName||t.shopName||"",error:s?.error||`任务 ${n.taskId} 推送失败`,shopDone:!0,submissionId:pe(n.taskId,a.shopName||t.shopName)}]}),await R(),y.value=`任务 ${n.taskId} 推送失败,已自动继续下一个任务`,M();continue}Le(n.taskId),y.value=h.value.length>0?`任务 ${n.taskId} 已入队,等待完成后自动继续下一个(剩余 ${h.value.length} 条)`:`任务 ${n.taskId} 已入队,等待执行完成`}y.value="串行队列已执行完成",await R(),f.success("查询ASIN队列已按顺序执行完成")}catch(e){if(_)return;const t=e instanceof Error?e.message:"队列执行失败";y.value=t,f.error(t),await R()}finally{C.value=!1,Y.value=!1,W(),E()}}}async function st(){ee.value=!0,P();const e=ie.value;if(!e.length){f.warning("请先匹配可用店铺");return}h.value=Ve(h.value,e),E(),y.value=`已加入 ${e.length} 条店铺,开始串行执行`,await Ae()}async function at(e){if(!e.resultId)return;const t=It(e.resultId),n=e.outputFilename||`${e.shopName||"result"}.xlsx`,a=await bt(t,n,`query-asin:${e.resultId}`);a.success?f.success(`已保存: ${a.path||n}`):a.error&&a.error!=="用户取消"&&f.error(a.error)}async function Ne(e){try{if(e.taskId)await St(e.taskId),c.value===e.taskId&&M(),ne(e.taskId);else if(e.resultId)await Tt(e.resultId),ne(e.taskId);else throw new Error("缺少可删除的任务标识");await Promise.all([F(),R()]),P(),f.success("已删除")}catch(t){if(Ue(t)){e.taskId&&c.value===e.taskId&&M(),ne(e.taskId),He(e),await F(),P(),f.success("后端记录已不存在,已同步移除本地记录");return}f.error(t instanceof Error?t.message:"删除失败")}}return ot(async()=>{Oe(),Be(),xe(),await Promise.all([F(),K(),oe()]),Se(),(c.value||h.value.length)&&(ee.value=!0,y.value=c.value!=null?`检测到未完成队列,继续等待任务 ${c.value} 完成并自动接续后续店铺`:`检测到未完成队列,继续执行剩余 ${h.value.length} 条店铺`,Ae())}),lt(()=>{_=!0,W(),Qe(),N.clearScope()}),(e,t)=>{const n=it,a=ct,l=dt;return u(),i("div",Dt,[v(rt,{active:"query-asin"}),o("div",Mt,[o("aside",Pt,[t[3]||(t[3]=o("div",{class:"section-title"},"店铺输入",-1)),o("div",Ft,[t[1]||(t[1]=o("div",{class:"hint"}," 左侧负责录入店铺并加入备选区,确认命中后推送到 Python 队列。查询ASIN按店铺串行执行:上一个任务完成后会自动开始下一个,失败也会继续下一个。 ",-1)),o("div",Rt,[v(n,{modelValue:O.value,"onUpdate:modelValue":t[0]||(t[0]=s=>O.value=s),clearable:"",placeholder:"请输入店铺名后回车或点击添加",onKeyup:ut(Ce,["enter"])},null,8,["modelValue"]),o("button",{type:"button",class:"opt-btn",disabled:x.value,onClick:Ce},r(x.value?"添加中...":"添加"),9,Ot)])]),t[4]||(t[4]=o("div",{class:"section-title"},"备选区",-1)),G.value.length?(u(),i("div",xt,[v(l,{data:G.value,"row-key":"id",height:"260",class:"candidate-table",onSelectionChange:Je},{default:S(()=>[v(a,{type:"selection",width:"42"}),v(a,{prop:"shop_name",label:"店铺名","min-width":"140","show-overflow-tooltip":""}),v(a,{label:"操作",width:"72",align:"center"},{default:S(({row:s})=>[o("button",{type:"button",class:"link-danger",onClick:g=>Ke(s.id)}," 删除 ",8,Lt)]),_:1})]),_:1},8,["data"])])):(u(),i("div",Bt," 暂无备选店铺,请先输入并添加 ")),o("div",Ut,[o("button",{type:"button",class:"btn-run",disabled:L.value,onClick:Xe},r(L.value?"匹配中...":"匹配店铺"),9,Ht),o("button",{type:"button",class:"btn-run btn-queue",disabled:ce.value||!ie.value.length,onClick:st},r(ce.value?"串行执行中...":"推送到 Python 队列"),9,Vt)]),t[5]||(t[5]=o("p",{class:"loading-msg"}," 当前页面会按店铺串行推送任务,并在任务成功或失败后自动接续下一个任务。服务端临时重启时会自动重试查询状态,恢复后继续后续店铺。 ",-1)),y.value?(u(),i("div",zt,[t[2]||(t[2]=o("div",{class:"section-title queue-debug-title"},"队列状态",-1)),o("div",jt,r(y.value),1),Z.value?(u(),i("pre",Jt,r(Z.value),1)):p("",!0)])):p("",!0)]),o("section",Kt,[t[14]||(t[14]=o("div",{class:"panel-header"},"匹配与任务",-1)),o("div",Wt,[o("div",Xt,[o("div",Gt,[t[6]||(t[6]=o("span",{class:"summary-label"},"备选店铺",-1)),o("strong",null,r(Q.value.candidateCount),1)]),o("div",Yt,[t[7]||(t[7]=o("span",{class:"summary-label"},"已处理任务",-1)),o("strong",null,r(Q.value.processedTaskCount),1)]),o("div",Zt,[t[8]||(t[8]=o("span",{class:"summary-label"},"成功任务",-1)),o("strong",null,r(Q.value.successTaskCount),1)]),o("div",es,[t[9]||(t[9]=o("span",{class:"summary-label"},"失败任务",-1)),o("strong",null,r(Q.value.failedTaskCount),1)])]),t[13]||(t[13]=o("div",{class:"subsection-title"},"匹配结果",-1)),m.value.length?(u(),ft(l,{key:1,data:m.value,"row-key":b,"highlight-current-row":!1,class:"result-table match-table"},{default:S(()=>[v(a,{prop:"shopName",label:"店铺名","min-width":"120"}),v(a,{label:"匹配",width:"72",align:"center"},{default:S(({row:s})=>[o("span",{class:re(s.matched?"ok":"fail")},r(s.matched?"是":"否"),3)]),_:1}),v(a,{prop:"shopId",label:"店铺 ID","min-width":"120","show-overflow-tooltip":""}),v(a,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),v(a,{prop:"companyName",label:"公司","min-width":"120","show-overflow-tooltip":""}),v(a,{label:"状态",width:"110","show-overflow-tooltip":""},{default:S(({row:s})=>[$e(r(Me(s.matchStatus)),1)]),_:1}),v(a,{label:"说明","min-width":"180","show-overflow-tooltip":""},{default:S(({row:s})=>[$e(r(Pe(s)),1)]),_:1}),v(a,{label:"操作",width:"72",align:"center"},{default:S(({row:s})=>[o("button",{type:"button",class:"link-danger",onClick:g=>Ge(s)}," 删除 ",8,ss)]),_:1})]),_:1},8,["data"])):(u(),i("div",ts," 完成“匹配店铺”后,这里会展示匹配结果。 ")),o("div",as,[t[12]||(t[12]=o("div",{class:"result-list-header"},[o("span",null,"任务记录")],-1)),!U.value.length&&!te.value.length?(u(),i("div",ns," 暂无任务记录。推送到 Python 队列后,这里会展示当前任务和历史任务。 ")):(u(),i(ue,{key:1},[U.value.length?(u(),i("div",os,[t[10]||(t[10]=o("div",{class:"result-subsection-title"},"当前任务",-1)),o("ul",ls,[(u(!0),i(ue,null,Ee(U.value,s=>(u(),i("li",{key:`${s.resultId}-${s.taskId}`,class:"task-item"},[o("div",rs,[o("span",{class:"id",title:s.shopName||""},r(s.shopName||"-"),9,us),o("div",is,"任务 ID: "+r(s.taskId??"-"),1),s.resultId?(u(),i("div",cs," 结果 ID: "+r(s.resultId),1)):p("",!0),s.shopId?(u(),i("div",ds," 店铺 ID: "+r(s.shopId),1)):p("",!0),s.platform?(u(),i("div",fs," 平台: "+r(s.platform),1)):p("",!0),o("div",hs," 开始时间: "+r(D(be(s.taskId))),1),o("div",vs," 创建时间: "+r(D(s.createdAt)),1),o("div",ps," ASIN结构: "+r(ye(s)),1),s.error?(u(),i("div",ys," 错误: "+r(s.error),1)):p("",!0)]),o("div",ms,[o("span",{class:re(["status",_e(s.taskStatus)])},r(we(s.taskStatus)),3),o("button",{type:"button",class:"btn-delete",onClick:g=>Ne(s)}," 删除 ",8,gs)])]))),128))])])):p("",!0),te.value.length?(u(),i("div",ws,[t[11]||(t[11]=o("div",{class:"result-subsection-title"},"历史任务",-1)),o("ul",_s,[(u(!0),i(ue,null,Ee(te.value,s=>(u(),i("li",{key:`${s.resultId}-${s.taskId}`,class:"task-item"},[o("div",ks,[o("span",{class:"id",title:s.shopName||""},r(s.shopName||"-"),9,Is),o("div",bs,"任务 ID: "+r(s.taskId??"-"),1),s.resultId?(u(),i("div",Ss," 结果 ID: "+r(s.resultId),1)):p("",!0),s.shopId?(u(),i("div",Ts," 店铺 ID: "+r(s.shopId),1)):p("",!0),s.platform?(u(),i("div",Cs," 平台: "+r(s.platform),1)):p("",!0),o("div",As," 开始时间: "+r(D(be(s.taskId))),1),o("div",Ns," 创建时间: "+r(D(s.createdAt)),1),s.finishedAt?(u(),i("div",$s," 完成时间: "+r(D(s.finishedAt)),1)):p("",!0),o("div",Es," ASIN结构: "+r(ye(s)),1),s.error?(u(),i("div",qs," 错误: "+r(s.error),1)):p("",!0)]),o("div",Qs,[o("span",{class:re(["status",_e(s.taskStatus)])},r(we(s.taskStatus)),3),Re(s)?(u(),i("button",{key:0,type:"button",class:"archive",onClick:g=>at(s)}," 下载结果 ",8,Ds)):p("",!0),o("button",{type:"button",class:"btn-delete",onClick:g=>Ne(s)}," 删除 ",8,Ms)])]))),128))])])):p("",!0)],64))])])])])])}}}),Fs=At(Ps,[["__scopeId","data-v-c2e27ea1"]]);Nt.locale("zh-cn");$t(Fs).use(Et,{locale:qt}).mount("#app"); diff --git a/app/assets/shop-match.js b/app/assets/shop-match.js index 0a9dfd1..a3272ca 100644 --- a/app/assets/shop-match.js +++ b/app/assets/shop-match.js @@ -1 +1 @@ -import{d as ds,g as m,o as fs,M as hs,a as i,c,b,B as vs,e as l,ad as ps,ae as ms,t as v,af as A,ag as gs,ah as ys,F as V,r as j,ai as St,n as pe,f as E,aj as Ss,ak as kt,al as ks,am as ws,w as _s,v as bs,aB as Ts,y as me,h as ge,aC as Cs,aD as Es,aE as Is,aF as Ds,E as p,aG as $s,aH as Ns,aI as Ms,aJ as Ps,s as xs,aK as As,aL as Ls,i as wt,aM as Fs,aN as Us,aO as Ue,aP as Rs,V as Os,_ as Vs,aQ as Bs,q as Hs,u as qs}from"./java-modules-DzYrjxib.js";import{z as zs}from"./zh-cn-z8KAT-CE.js";/* empty css */import{L as js}from"./listingFilters-BpGOU_pJ.js";import{c as Ks}from"./categorized-timers-JPA-olTr.js";const Gs={class:"page-shell module-page"},Js={class:"main-content"},Ys={class:"left-panel"},Qs={class:"input-zone"},Ws={class:"input-row"},Xs=["disabled"],Zs={key:0,class:"empty-candidates"},ea={key:1,class:"candidate-table-scroll"},ta=["onClick"],sa={class:"country-pref-checks"},aa=["checked","disabled","onChange"],na={class:"country-check-text"},oa={key:2,class:"country-order-panel"},la={class:"country-order-list"},ra=["onDragstart","onDrop"],ua={class:"country-drag-label"},ia={key:3,class:"country-pref-status"},ca={class:"listing-filter-row"},da={class:"schedule-switch"},fa=["disabled"],ha={key:4,class:"schedule-config"},va=["disabled","onClick"],pa=["disabled"],ma={class:"run-row"},ga=["disabled"],ya=["disabled"],Sa={key:5,class:"queue-debug-card"},ka={class:"queue-debug-line"},wa={key:0,class:"queue-debug-payload"},_a={class:"right-panel"},ba={class:"task-list-wrap"},Ta={class:"clean-result-summary"},Ca={class:"summary-card"},Ea={class:"summary-card"},Ia={class:"summary-card"},Da={class:"summary-card"},$a={key:0,class:"empty-tasks narrow"},Na=["onClick"],Ma={class:"result-list-wrap"},Pa={key:0,class:"empty-tasks"},xa={key:0,class:"result-subsection"},Aa={class:"task-list"},La={class:"left split-result-main"},Fa=["title"],Ua={class:"files"},Ra={key:0,class:"files"},Oa={key:1,class:"files"},Va={key:2,class:"files"},Ba={key:3,class:"files"},Ha={class:"task-right"},qa=["onClick"],za=["onClick"],ja={key:1,class:"result-subsection"},Ka={class:"task-list"},Ga={class:"left split-result-main"},Ja=["title"],Ya={class:"files"},Qa={key:0,class:"files"},Wa={key:1,class:"files"},Xa={class:"task-right"},Za=["onClick"],en=["onClick"],tn=ds({__name:"BrandShopMatchTab",setup(an){const ye=[{code:"DE",label:"德国"},{code:"UK",label:"英国"},{code:"FR",label:"法国"},{code:"IT",label:"意大利"},{code:"ES",label:"西班牙"}],ae=m(""),Se=m([]),Re=m([]),T=m([]),ke=m("Active"),ne=m(!1),oe=m(!1),P=m(!1),we=m(!1),_e=m(!1),S=m(""),K=m(""),g=m(["DE","UK","FR","IT","ES"]),G=m(null),be=m(!1),Te=m(!1);let B=null;const x=m(!0),k=m([$e()]),J=m({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),D=m([]),y=m([]),w=m({}),d=m({}),M=m(null),Ce=m(!1),N=new Map,Ee=m(!1);let Y=null,Oe=0,Ve="",_=!1;const C=Ks("shop-match"),Ie=ge(()=>Je(D.value.filter(e=>!!I(e.taskId)&&!Xe(e)),d.value,"current")),De=ge(()=>Je(D.value.filter(e=>!I(e.taskId)||Xe(e)),d.value,"history")),_t=ge(()=>Ie.value.length>0||De.value.length>0),bt=ge(()=>{const e=new Set(g.value);return[...g.value.map(t=>({code:t,label:Ke(t)})),...ye.filter(t=>!e.has(t.code)).map(t=>({code:t.code,label:t.label}))]});function Q(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function Tt(){const e=Number(Q());return Number.isFinite(e)&&e>0?e:0}function I(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:0}function Be(){return`shop-match:tasks:${Q()}`}function He(){return`shop-match:task-status:${Q()}`}function qe(){return`shop-match:task-snapshots:${Q()}`}function ze(){return`shop-match:matched-items:${Q()}`}function le(e,t,s){s?window.localStorage.removeItem(e):window.localStorage.setItem(e,JSON.stringify(t))}function L(e){return`${(e.shopName||"").trim()}::${e.shopId||""}`}function je(e){return`${I(e.taskId)}-${e.resultId||0}-${e.shopName||""}`}function Ke(e){return ye.find(t=>t.code===e)?.label||e}function Ct(e){const t=e.getFullYear(),s=String(e.getMonth()+1).padStart(2,"0"),a=String(e.getDate()).padStart(2,"0"),n=String(e.getHours()).padStart(2,"0"),u=String(e.getMinutes()).padStart(2,"0"),r=String(e.getSeconds()).padStart(2,"0");return`${t}-${s}-${a}T${n}:${u}:${r}`}function re(e){const t=e.getFullYear(),s=String(e.getMonth()+1).padStart(2,"0"),a=String(e.getDate()).padStart(2,"0"),n=String(e.getHours()).padStart(2,"0"),u=String(e.getMinutes()).padStart(2,"0");return`${t}-${s}-${a} ${n}:${u}:00`}function $e(){const e=new Date;return e.setSeconds(0,0),e.setMinutes(e.getMinutes()+5),re(e)}function W(e){if(!e)return null;const s=e.trim().replace("T"," ").match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})(?::(\d{2}))?$/);if(!s)return null;const a=Number(s[1]),n=Number(s[2]),u=Number(s[3]),r=Number(s[4]),f=Number(s[5]),o=Number(s[6]||"0"),h=new Date(a,n-1,u,r,f,o,0);return Number.isNaN(h.getTime())||h.getFullYear()!==a||h.getMonth()!==n-1||h.getDate()!==u?null:h}function Et(e,t){const s=W(e)||new Date;return s.setSeconds(0,0),s.setMinutes(s.getMinutes()+t),re(s)}function Ge(e){const t=W(e);if(!t)return"-";const s=String(t.getMonth()+1).padStart(2,"0"),a=String(t.getDate()).padStart(2,"0"),n=String(t.getHours()).padStart(2,"0"),u=String(t.getMinutes()).padStart(2,"0");return`${s}-${a} ${n}:${u}`}function Je(e,t,s){const a=new Map;for(const n of e)a.set(je(n),n);for(const[n,u]of Object.entries(t)){const r=I(n),f=u.items?.[0];if(!f||!r)continue;const o=We(r);if(s==="current"&&o||s==="history"&&!o)continue;const h=je({...f,taskId:r});a.has(h)||a.set(h,{...f,taskId:r})}return Array.from(a.values())}function It(){try{const e=window.localStorage.getItem(Be()),t=e?JSON.parse(e):[];y.value=Array.isArray(t)?t.filter(s=>typeof s=="number"&&s>0):[]}catch{y.value=[]}}function ue(){le(Be(),y.value,y.value.length===0)}function Dt(){try{const e=window.localStorage.getItem(He());w.value=e?JSON.parse(e):{}}catch{w.value={}}}function F(){le(He(),w.value,Object.keys(w.value).length===0)}function $t(){try{const e=window.localStorage.getItem(qe());d.value=e?JSON.parse(e):{}}catch{d.value={}}}function H(){le(qe(),d.value,Object.keys(d.value).length===0)}function Nt(){try{const e=window.localStorage.getItem(ze());T.value=e?JSON.parse(e):[]}catch{T.value=[]}}function Ne(){le(ze(),T.value,T.value.length===0)}function Mt(e){const t=e instanceof Error?e.message:String(e||"");return/记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(t)}function Pt(){const e=y.value.filter(t=>(w.value[t]||d.value[t]?.task?.status)==="RUNNING");e.length!==y.value.length&&(y.value=e,ue())}function Ye(e){y.value.includes(e)||(y.value=[...y.value,e],ue())}function ie(e){const t=N.get(e);t&&(C.clearTimer("scheduled-dispatch",t),N.delete(e),N.size||fe())}function ce(e){if(ie(e),y.value=y.value.filter(t=>t!==e),delete w.value[e],d.value[e]){const t={...d.value};delete t[e],d.value=t,H()}ue(),F()}function X(e){ce(e),D.value=D.value.filter(t=>I(t.taskId)!==e)}function Qe(e,t=!0){y.value=y.value.filter(s=>s!==e),t||delete w.value[e],ue(),F()}function Z(e){return e==="SUCCESS"||e==="FAILED"||e==="COMPLETED"}function We(e){if(!e)return!1;const t=w.value[e]||d.value[e]?.task?.status;return Z(t)}function Xe(e){const t=I(e.taskId);return t&&We(t)||Z(e.taskStatus)?!0:!!e.success}async function ee(){Se.value=await Cs()}async function U(){J.value=await Es()}async function q(){const e=await Is();D.value=e.items||[]}async function xt(){try{const e=await Ds();if(Te.value)return;const t=(e.country_codes||[]).filter(s=>ye.some(a=>a.code===s));t.length&&(g.value=t)}catch{}}async function de(){await Promise.allSettled([q(),U()])}function Ze(){B&&C.clearTimer("preference-save",B),B=C.setTimeout("preference-save",()=>{B=null,At()},450)}async function At(){if(g.value.length){be.value=!0;try{await Us(g.value)}catch(e){p.error(e instanceof Error?e.message:"保存国家配置失败")}finally{be.value=!1}}}function Lt(e){Re.value=e}async function et(){const e=ae.value.trim();if(!e){p.warning("请输入店铺名");return}ne.value=!0;try{await $s(e),ae.value="",await ee(),await U()}catch(t){p.error(t instanceof Error?t.message:"添加失败")}finally{ne.value=!1}}async function Ft(e){try{await Ns(e.id),await ee(),await U()}catch(t){p.error(t instanceof Error?t.message:"删除失败")}}function Ut(e){return g.value.includes(e)}function tt(e){return g.value.length===1&&g.value[0]===e}function Rt(e,t){const s=t.target;if(s){if(!s.checked&&tt(e)){s.checked=!0,p.warning("至少保留 1 个国家");return}Ot(e,s.checked)}}function Ot(e,t){if(Te.value=!0,t)g.value.includes(e)||(g.value=[...g.value,e]);else{if(g.value.length<=1){p.warning("至少保留 1 个国家");return}g.value=g.value.filter(s=>s!==e)}Ze()}function Vt(e){G.value=e}function Bt(){G.value=null}function Ht(e){const t=G.value;if(G.value=null,t==null||t===e)return;Te.value=!0;const s=[...g.value],[a]=s.splice(t,1);s.splice(e,0,a),g.value=s,Ze()}function qt(){x.value&&(k.value=Me(k.value,!0)),x.value||(k.value=[])}function zt(){const e=k.value[k.value.length-1],t=e?Et(e,60):$e();k.value=[...k.value,t]}function jt(e){k.value.length<=1||(k.value=k.value.filter((t,s)=>s!==e))}function Kt(e,t){const s=[...k.value];s[e]=t||"",k.value=Me(s,!1)}function Gt(e,t){const s=new Map;for(const a of e)s.set(L(a),a);for(const a of t)s.set(L(a),a);return Array.from(s.values())}async function Jt(){const e=Re.value.map(t=>t.shop_name).filter(Boolean);if(!e.length){p.warning("请先选择候选店铺");return}oe.value=!0;try{const t=await Ms(e);T.value=Gt(T.value,t.items||[]),Ne(),_e.value&&mt(),p.success(`本次返回 ${t.items?.length||0} 条匹配结果`)}catch(t){p.error(t instanceof Error?t.message:"匹配失败")}finally{oe.value=!1}}function Yt(e){T.value=T.value.filter(t=>L(t)!==L(e)),Ne()}function R(e){const t=new Set(e.map(s=>L(s)));T.value=T.value.filter(s=>!t.has(L(s))),Ne()}function Qt(){if(!x.value)return;const e=Date.now(),t=k.value.map(n=>n.trim()).filter(Boolean);if(!t.length)throw new Error("请至少选择一个执行时间");const s=t.map(n=>{const u=W(n);if(!u)throw new Error(`时间格式无效: ${n}`);return{raw:Ct(u),picker:re(u),time:u.getTime()}}).sort((n,u)=>n.time-u.time);for(let n=1;nn.time>e);if(!a.length)throw new Error("执行时间必须晚于当前时间,请重新选择");return a.length!==s.length&&(k.value=a.map(n=>n.picker),p.warning("已自动移除早于当前时间的执行时间")),a.map(n=>n.raw)}function Me(e,t){const s=Date.now(),a=e.map(r=>r.trim()).filter(Boolean).map(r=>{const f=W(r);return f?{value:re(f),time:f.getTime()}:null}).filter(r=>!!r).filter(r=>r.time>s).sort((r,f)=>r.time-f.time),n=[],u=new Set;for(const r of a)u.has(r.value)||(u.add(r.value),n.push(r.value));return!n.length&&t?[$e()]:n}function Wt(e){return e.skipAsinsByCountry||e.skip_asins_by_country||{}}function Xt(e){return e.skipAsinDetailsByCountry||e.skip_asin_details_by_country||{}}function st(e,t,s,a,n=!0){const u=Wt(t),r=Xt(t);return{type:"shop-match-run",ts:Date.now(),data:{taskId:e,user_id:Tt(),items:[{shopName:t.shopName,shopId:t.shopId,platform:t.platform,companyName:t.companyName,matched:!0,matchStatus:t.matchStatus,matchMessage:t.matchMessage,skip_asins_by_country:u,skipAsinsByCountry:u,skip_asin_details_by_country:r,skipAsinDetailsByCountry:r}],country_codes:[...s],skip_asins_by_country:u,skipAsinsByCountry:u,skip_asin_details_by_country:r,skipAsinDetailsByCountry:r,risk_listing_filter:ke.value,stage_index:a,final_stage:n}}}function Pe(e){const t=d.value[e]?.task,s=t?.scheduleStages||[],a=t?.currentStageIndex;if(typeof a!="number")return null;const n=s.find(u=>u.stageIndex===a);return n?.scheduledAt?{stageIndex:a,scheduledAt:n.scheduledAt,finalStage:a===s.length-1}:null}async function Zt(e,t){const s=wt();if(!s?.enqueue_json)throw new Error("当前客户端未提供 enqueue_json");const a=Pe(e),n=d.value[e],u=n?.task?.countryCodes||g.value;if(!a)throw new Error(`任务 ${e} 缺少待执行阶段`);ie(e),await ot(()=>Rs(e,a.stageIndex),(o,h)=>{S.value=`任务 ${e} 等待后端恢复后再激活执行(${o}/${h})...`}),w.value={...w.value,[e]:"RUNNING"},n?.task&&(d.value={...d.value,[e]:{...n,task:{...n.task,status:"RUNNING",activeStageIndex:a.stageIndex}}}),H(),F();const r=st(e,t,u,a.stageIndex,a.finalStage);K.value=JSON.stringify(r,null,2);const f=await s.enqueue_json(r);if(!f?.success)throw new Error(f?.error||`任务 ${e} 推送失败`);Ye(e),S.value=`任务 ${e} 已推送第 ${a.stageIndex+1} 轮`,se(!0)}function at(e){const t=W(e);return t?t.getTime():Number.NaN}function es(){const e=new Set(y.value);for(const s of Object.keys(d.value)){const a=I(s);a>0&&e.add(a)}for(const s of D.value){const a=I(s.taskId);a>0&&e.add(a)}const t=Array.from(e).map(s=>{const a=d.value[s],n=w.value[s]||a?.task?.status,u=a?.items?.[0]||D.value.find(o=>I(o.taskId)===s),r=Pe(s);if(n!=="SCHEDULED"||!u||!r?.scheduledAt)return null;const f=at(r.scheduledAt);return!Number.isFinite(f)||f>Date.now()?null:{taskId:s,item:u,scheduledTime:f}}).filter(s=>!!s);return t.sort((s,a)=>s.scheduledTime-a.scheduledTime||s.taskId-a.taskId),t}async function xe(){if(Ee.value)return;const e=es();if(e.length){Ee.value=!0;try{const t=e[0];try{await Zt(t.taskId,t.item),await ls(t.taskId)}catch(s){const a=s instanceof Error?s.message:`任务 ${t.taskId} 调度失败`,n=`${t.taskId}:${a}`,u=Date.now();S.value=a,(Ve!==n||u-Oe>1e4)&&(Ve=n,Oe=u,p.error(a)),await Promise.allSettled([q(),lt()])}}finally{Ee.value=!1,$()}}}function ts(e,t){if(_||!t)return;ie(e);const s=at(t);if(!Number.isFinite(s))return;const a=Math.max(0,s-Date.now()),n=C.setTimeout("scheduled-dispatch",()=>{N.delete(e),N.size||fe(),_||xe()},a);N.set(e,n),nt()}function $(){if(_)return;const e=new Set(y.value);for(const t of Object.keys(d.value)){const s=I(t);s>0&&e.add(s)}for(const t of D.value){const s=I(t.taskId);s>0&&e.add(s)}for(const t of e){const a=d.value[t]?.task?.status||w.value[t],n=Pe(t);a==="SCHEDULED"&&n?.scheduledAt?ts(t,n.scheduledAt):ie(t)}N.size?nt():fe(),xe()}function nt(){_||Y||!N.size||(Y=C.setInterval("schedule-heartbeat",()=>{_||xe()},3e4))}function fe(){Y&&(C.clearTimer("schedule-heartbeat",Y),Y=null)}function he(){$(),y.value.length&&se(!0)}const ss=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"];function te(e){return _?Promise.resolve():C.sleep("queue-wait",e)}function as(){C.clearCategory("queue-wait")}function Ae(e){const t=(e instanceof Error?e.message:String(e||"")).toLowerCase();return ss.some(s=>t.includes(s.toLowerCase()))}async function ot(e,t,s=10){let a=0;for(;;){if(_)throw new Error("component disposed");try{return await e()}catch(n){if(a+=1,!Ae(n)||a>=s)throw n;t(a,s),await te(O())}}}async function lt(){if(!y.value.length)return{settledTaskIds:[]};try{const e=await Ue(y.value),t={...d.value},s=new Set;for(const a of e.missingTaskIds||[])X(a),delete t[a],s.add(a);for(const a of e.items||[]){const n=a.task?.id;if(!n)continue;const u=t[n];t[n]=u?{...u,task:{...u.task||{},...a.task||{}}}:a;const r=a.task?.status||"";if(r){if(w.value[n]=r,Z(r)){ce(n),s.add(n);continue}r==="SCHEDULED"&&(Qe(n),s.add(n))}}return d.value=t,H(),F(),$(),{settledTaskIds:Array.from(s)}}catch{return{settledTaskIds:[]}}}function O(){return Os()}function rt(e=!1){if(_)return;if(M.value){if(!e)return;C.clearTimer("task-poll",M.value),M.value=null}const t=async()=>{if(M.value=null,!_){if(Ce.value||!y.value.length){y.value.length&&rt();return}Ce.value=!0;try{const{settledTaskIds:s}=await lt();s.length&&await Promise.allSettled([q(),U()])}finally{Ce.value=!1}!_&&y.value.length&&(M.value=C.setTimeout("task-poll",t,O()))}};e?t():M.value=C.setTimeout("task-poll",t,O())}function se(e=!1){rt(e)}function ns(){M.value&&(C.clearTimer("task-poll",M.value),M.value=null)}async function os(e){let t=0;const s=30;for(;;){if(_)return"STOPPED";try{const a=await Ue([e]);if(t>0&&(S.value=`任务 ${e} 后端已恢复,继续等待执行结果...`),t=0,(a.missingTaskIds||[]).includes(e))return X(e),await de(),$(),"FAILED";const n=(a.items||[]).find(r=>r.task?.id===e),u=n?.task?.status||"";if(n){const r=d.value[e];d.value={...d.value,[e]:r?{...r,task:{...r.task||{},...n.task||{}}}:n},H()}if(u&&(w.value[e]=u,F()),Z(u))return ce(e),await de(),$(),u}catch(a){if(!Ae(a))throw a;if(t+=1,t>=s)throw new Error(`任务 ${e} 等待后端恢复超时,请稍后手动刷新查看状态`);S.value=`任务 ${e} 运行中,正在等待后端服务恢复(${t}/${s})...`,(t===1||t%5===0)&&p.warning(`任务 ${e} 运行中,后端服务暂时不可用,正在自动重试`),await te(O());continue}await te(O())}}async function ls(e){let t=0;const s=30;for(;;){if(_)return"STOPPED";try{const a=await Ue([e]);if(t>0&&(S.value=`任务 ${e} 后端已恢复,继续等待当前轮次结束...`),t=0,(a.missingTaskIds||[]).includes(e))return X(e),await de(),$(),"FAILED";const n=(a.items||[]).find(r=>r.task?.id===e),u=n?.task?.status||"";if(n){const r=d.value[e];d.value={...d.value,[e]:r?{...r,task:{...r.task||{},...n.task||{}}}:n},H()}if(u&&(w.value[e]=u,F()),!u||u==="RUNNING"){await te(O());continue}return Z(u)?(ce(e),await de(),$(),u):(u==="SCHEDULED"&&(Qe(e),$()),u)}catch(a){if(!Ae(a))throw a;if(t+=1,t>=s)throw new Error(`任务 ${e} 等待当前轮次结束超时,请稍后手动刷新查看状态`);S.value=`任务 ${e} 运行中,正在等待当前轮次结束(${t}/${s})...`,(t===1||t%5===0)&&p.warning(`任务 ${e} 运行中,后端服务暂时不可用,正在自动重试`),await te(O())}}}function Le(e){const t=I(e.taskId);return t?w.value[t]||d.value[t]?.task?.status||e.taskStatus||"":e.taskStatus||""}function ut(e){const t=I(e.taskId);return t?d.value[t]:void 0}function it(e){const s=ut(e)?.task,a=s?.scheduleStages||[];if(!a.length)return"";const n=a.length,u=typeof s?.activeStageIndex=="number"?s.activeStageIndex:void 0,r=typeof s?.currentStageIndex=="number"?s.currentStageIndex:void 0;return typeof u=="number"?`执行进度: 第 ${u+1}/${n} 次执行中`:typeof r=="number"?`执行进度: 等待第 ${r+1}/${n} 次`:`执行进度: 共 ${n} 次`}function ct(e){const s=ut(e)?.task,a=s?.scheduleStages||[];if(typeof s?.currentStageIndex=="number"){const n=a.find(u=>u.stageIndex===s.currentStageIndex);if(n?.scheduledAt)return Ge(n.scheduledAt)}return e.scheduledAt?Ge(e.scheduledAt):""}function dt(e){const t=Le(e);return t==="SCHEDULED"?"待执行":t==="RUNNING"?"执行中":t==="SUCCESS"||t==="COMPLETED"?"已完成":t==="FAILED"?"失败":e.success?"已完成":"未知"}function ft(e){const t=Le(e);return t==="SUCCESS"||t==="COMPLETED"?"success":t==="FAILED"?"failed":"running"}function ht(e){const t=Le(e);return!!e.resultId&&(!!e.fileReady||!!e.downloadUrl)&&(t==="SUCCESS"||t==="COMPLETED")}async function vt(e){if(!e.resultId)return;const t=Ps(e.resultId),s=e.outputFilename||`${e.shopName||"result"}.xlsx`,a=await xs(t,s,`shop-match:${e.resultId}`);a.success?p.success(`已保存: ${a.path||s}`):a.error&&a.error!=="用户取消"&&p.error(a.error)}async function pt(e){const t=I(e.taskId),s=Number(e.resultId||0);try{if(t>0)await As(t),X(t);else if(s>0)await Ls(s),D.value=D.value.filter(a=>Number(a.resultId||0)!==s),R([e]);else throw new Error("缺少可删除的任务标识");await Promise.allSettled([q(),ee(),U()]),p.success("删除成功")}catch(a){if(Mt(a)){t>0?X(t):s>0&&(D.value=D.value.filter(n=>Number(n.resultId||0)!==s)),R([e]),await Promise.allSettled([q(),ee(),U()]),p.success("后端记录已不存在,本地记录已同步清理");return}p.error(a instanceof Error?a.message:"删除失败")}}function rs(e){const t=(e||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[t]||t||"—"}function us(e){const t=(e.matchMessage||"").trim();return t||(e.matched&&e.matchStatus==="MATCHED"?"紫鸟索引已命中,可推送队列":e.matched?"已关联索引,请结合状态列查看是否可推送":"未命中或未就绪,请检查店铺名与索引刷新")}async function is(){_e.value=!0,await mt()}function cs(){return T.value.find(e=>e.matched)}async function mt(){if(_||we.value)return;const e=wt();if(!e?.enqueue_json){p.error("当前客户端未提供 enqueue_json");return}if(!T.value.filter(r=>r.matched).length){p.warning("请先匹配可用店铺");return}if(!g.value.length){p.warning("请至少勾选一个国家");return}let s;try{s=Qt()}catch(r){p.error(r instanceof Error?r.message:"定时配置无效");return}we.value=!0,P.value=!0,K.value="";let a=0,n=0,u=0;try{for(;!_&&_e.value;){const r=cs();if(!r)break;u+=1;try{const f=await ot(()=>Fs([r],g.value,s),(Fe,ve)=>{S.value=`后端服务暂时不可用,正在重试创建任务(${Fe}/${ve})...`}),o=f.taskId,h=s?.length?"SCHEDULED":"RUNNING",z={task:{id:o,status:h,scheduledAt:s?.[0],countryCodes:[...g.value],currentStageIndex:s?.length?0:void 0,activeStageIndex:void 0,scheduleStages:(s||[]).map((Fe,ve)=>({stageIndex:ve,scheduledAt:Fe,status:ve===0?"SCHEDULED":"PENDING"}))},items:f.items};if(d.value={...d.value,[o]:z},w.value={...w.value,[o]:h},H(),F(),!f.items?.[0]){R([r]);continue}if(s?.length){a+=1,$(),S.value=`任务 ${o} 已创建,共 ${s.length} 个执行时间点`,R([r]);continue}const gt=st(o,r,g.value);K.value=JSON.stringify(gt,null,2);const yt=await e.enqueue_json(gt);if(!yt?.success){n+=1,S.value=`任务 ${o} 推送失败,已自动继续下一条:${yt?.error||"未知错误"}`,p.error(S.value),R([r]);continue}if(Ye(o),se(!0),R([r]),S.value=`任务 ${o} 已入队,等待执行完成`,await os(o)!=="SUCCESS"){n+=1,S.value=`任务 ${o} 执行失败,已自动继续下一条`,p.error(S.value);continue}a+=1,S.value=`任务 ${o} 已完成`}catch(f){if(_)break;n+=1,S.value=`第 ${u} 条任务处理失败,已自动继续下一条:${f instanceof Error?f.message:"未知错误"}`,p.error(S.value),R([r]);continue}}$(),s?.length||se(!0),!_&&(a>0||n>0)&&p.success(s?.length?`定时任务已创建:成功 ${a} 条,失败 ${n} 条`:`店铺推送已完成:成功 ${a} 条,失败 ${n} 条`)}catch(r){if(_)return;const f=r instanceof Error?r.message:"推送失败";S.value=f,p.error(f)}finally{we.value=!1,P.value=!1}}return fs(async()=>{It(),Dt(),$t(),Nt(),k.value=Me(k.value,x.value),Pt(),await Promise.allSettled([ee(),xt(),q(),U()]),window.addEventListener("focus",he),document.addEventListener("visibilitychange",he),$(),y.value.length&&se(!0)}),hs(()=>{_=!0,ns(),fe(),as(),window.removeEventListener("focus",he),document.removeEventListener("visibilitychange",he),B&&C.clearTimer("preference-save",B);for(const e of N.values())C.clearTimer("scheduled-dispatch",e);N.clear(),C.clearScope()}),(e,t)=>{const s=ms,a=gs,n=ys,u=ks,r=ws,f=Ts;return i(),c("div",Gs,[b(vs,{active:"shop-match"}),l("div",Js,[l("aside",Ys,[t[10]||(t[10]=l("div",{class:"section-title"},"店铺候选",-1)),l("div",Qs,[t[4]||(t[4]=l("div",{class:"hint"},"输入店铺名后点“添加”加入下方备选区。勾选备选店铺后先做“匹配店铺”,确认命中紫鸟索引后再推送到 Python 队列。",-1)),l("div",Ws,[b(s,{modelValue:ae.value,"onUpdate:modelValue":t[0]||(t[0]=o=>ae.value=o),clearable:"",placeholder:"请输入店铺名后回车或点击添加",onKeyup:ps(et,["enter"])},null,8,["modelValue"]),l("button",{type:"button",class:"opt-btn",disabled:ne.value,onClick:et},v(ne.value?"添加中...":"添加"),9,Xs)])]),t[11]||(t[11]=l("div",{class:"section-title"},"备选店铺",-1)),Se.value.length?(i(),c("div",ea,[b(n,{data:Se.value,"row-key":"id",height:"240",class:"candidate-table",onSelectionChange:Lt},{default:A(()=>[b(a,{type:"selection",width:"42"}),b(a,{prop:"shop_name",label:"店铺名","min-width":"120","show-overflow-tooltip":""}),b(a,{label:"操作",width:"72",align:"center"},{default:A(({row:o})=>[l("button",{type:"button",class:"link-danger",onClick:h=>Ft(o)},"删除",8,ta)]),_:1})]),_:1},8,["data"])])):(i(),c("div",Zs,"暂无备选店铺,请先输入并添加")),t[12]||(t[12]=l("div",{class:"section-title"},"国家配置",-1)),t[13]||(t[13]=l("p",{class:"hint country-pref-hint"},"勾选的国家会在每一个执行时间点都执行一遍。勾选区会按照已选顺序排在前面,下方支持拖拽排序,和商品风险页保持一致。",-1)),l("div",sa,[(i(!0),c(V,null,j(bt.value,o=>(i(),c("label",{key:o.code,class:"country-check-row"},[l("input",{type:"checkbox",class:"country-check-input",checked:Ut(o.code),disabled:tt(o.code),onChange:h=>Rt(o.code,h)},null,40,aa),l("span",na,v(o.label)+" ("+v(o.code)+")",1)]))),128))]),g.value.length?(i(),c("div",oa,[t[6]||(t[6]=l("div",{class:"country-order-caption"},"已选顺序(拖拽 ⋮⋮ 调整)",-1)),l("div",la,[(i(!0),c(V,null,j(g.value,(o,h)=>(i(),c("div",{key:o,class:pe(["country-drag-row",{dragging:G.value===h}]),draggable:"true",onDragstart:z=>Vt(h),onDragend:Bt,onDragover:t[1]||(t[1]=St(()=>{},["prevent"])),onDrop:St(z=>Ht(h),["prevent"])},[t[5]||(t[5]=l("span",{class:"drag-handle",title:"拖动排序"},"⋮⋮",-1)),l("span",ua,v(Ke(o))+" ("+v(o)+")",1)],42,ra))),128))])])):E("",!0),be.value?(i(),c("div",ia,"保存中...")):E("",!0),t[14]||(t[14]=l("div",{class:"section-title"},"商品列表筛选",-1)),t[15]||(t[15]=l("p",{class:"hint listing-filter-hint"},"与“推送到 Python 队列”一并下发,供 Python 区分处理场景。",-1)),l("div",ca,[b(r,{modelValue:ke.value,"onUpdate:modelValue":t[2]||(t[2]=o=>ke.value=o),class:"listing-filter-select",teleported:"",placeholder:"选择筛选类型"},{default:A(()=>[(i(!0),c(V,null,j(Ss(js),o=>(i(),kt(u,{key:o.value,label:o.label,value:o.value},null,8,["label","value"]))),128))]),_:1},8,["modelValue"])]),t[16]||(t[16]=l("div",{class:"section-title"},"定时执行",-1)),l("label",da,[_s(l("input",{"onUpdate:modelValue":t[3]||(t[3]=o=>x.value=o),type:"checkbox",disabled:P.value,onChange:qt},null,40,fa),[[bs,x.value]]),t[7]||(t[7]=l("span",null,"启用多时间点调度",-1))]),x.value?(i(),c("div",ha,[(i(!0),c(V,null,j(k.value,(o,h)=>(i(),c("div",{key:`schedule-${h}`,class:"schedule-row"},[b(f,{"model-value":o,type:"datetime","value-format":"YYYY-MM-DD HH:mm:ss",format:"MM-DD HH:mm",placeholder:"选择执行时间",disabled:P.value,class:"schedule-picker","onUpdate:modelValue":z=>Kt(h,z)},null,8,["model-value","disabled","onUpdate:modelValue"]),l("button",{type:"button",class:"schedule-remove",disabled:P.value||k.value.length<=1,onClick:z=>jt(h)},"删除",8,va)]))),128)),l("button",{type:"button",class:"schedule-add",disabled:P.value,onClick:zt},"添加时间点",8,pa),t[8]||(t[8]=l("p",{class:"hint schedule-hint"},"默认开启定时;支持按 `MM-DD HH:mm` 配置多个时间点,前端不再限制选择更早时间,实际是否可执行以后端校验为准。",-1))])):E("",!0),l("div",ma,[l("button",{type:"button",class:"btn-run",disabled:oe.value,onClick:Jt},v(oe.value?"匹配中...":"匹配店铺"),9,ga),l("button",{type:"button",class:"btn-run btn-queue",disabled:P.value||!T.value.length,onClick:is},v(P.value?"推送中...":x.value?"创建定时任务":"推送到 Python 队列"),9,ya)]),t[17]||(t[17]=l("p",{class:"loading-msg"},[me("已支持多阶段定时执行;Python 每处理完一店可回传 "),l("code",null,"/api/shop-match/tasks/{taskId}/result"),me(",后端会按阶段汇总并在超时场景自动收尾。")],-1)),S.value?(i(),c("div",Sa,[t[9]||(t[9]=l("div",{class:"section-title queue-debug-title"},"推送结果",-1)),l("div",ka,v(S.value),1),K.value?(i(),c("pre",wa,v(K.value),1)):E("",!0)])):E("",!0)]),l("section",_a,[t[26]||(t[26]=l("div",{class:"panel-header"},"匹配与任务",-1)),l("div",ba,[l("div",Ta,[l("div",Ca,[t[18]||(t[18]=l("span",{class:"summary-label"},"候选店铺",-1)),l("strong",null,v(J.value.candidateCount),1)]),l("div",Ea,[t[19]||(t[19]=l("span",{class:"summary-label"},"已结束任务",-1)),l("strong",null,v(J.value.processedTaskCount),1)]),l("div",Ia,[t[20]||(t[20]=l("span",{class:"summary-label"},"成功",-1)),l("strong",null,v(J.value.successTaskCount),1)]),l("div",Da,[t[21]||(t[21]=l("span",{class:"summary-label"},"失败",-1)),l("strong",null,v(J.value.failedTaskCount),1)])]),t[25]||(t[25]=l("div",{class:"subsection-title"},"匹配结果",-1)),T.value.length?(i(),kt(n,{key:1,data:T.value,"row-key":L,"highlight-current-row":!1,class:"result-table match-table"},{default:A(()=>[b(a,{prop:"shopName",label:"店铺名","min-width":"100"}),b(a,{label:"匹配",width:"72",align:"center"},{default:A(({row:o})=>[l("span",{class:pe(o.matched?"ok":"fail")},v(o.matched?"是":"否"),3)]),_:1}),b(a,{prop:"shopId",label:"店铺ID","min-width":"120","show-overflow-tooltip":""}),b(a,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),b(a,{prop:"companyName",label:"公司","min-width":"100","show-overflow-tooltip":""}),b(a,{label:"状态",width:"100","show-overflow-tooltip":""},{default:A(({row:o})=>[me(v(rs(o.matchStatus)),1)]),_:1}),b(a,{label:"说明","min-width":"140","show-overflow-tooltip":""},{default:A(({row:o})=>[me(v(us(o)),1)]),_:1}),b(a,{label:"操作",width:"72",align:"center"},{default:A(({row:o})=>[l("button",{type:"button",class:"link-danger",onClick:h=>Yt(o)},"删除",8,Na)]),_:1})]),_:1},8,["data"])):(i(),c("div",$a,"完成“匹配店铺”后,在此展示紫鸟索引匹配结果,供核对后再推送队列。")),l("div",Ma,[t[24]||(t[24]=l("div",{class:"result-list-header"},[l("span",null,"处理记录")],-1)),_t.value?(i(),c(V,{key:1},[Ie.value.length?(i(),c("div",xa,[t[22]||(t[22]=l("div",{class:"result-subsection-title"},"当前任务",-1)),l("ul",Aa,[(i(!0),c(V,null,j(Ie.value,o=>(i(),c("li",{key:`cur-${o.resultId}-${o.taskId}`,class:"task-item"},[l("div",La,[l("span",{class:"id",title:o.shopName||""},v(o.shopName||"-"),9,Fa),l("div",Ua,"任务 ID: "+v(o.taskId??"-"),1),o.platform?(i(),c("div",Ra,"平台: "+v(o.platform),1)):E("",!0),it(o)?(i(),c("div",Oa,v(it(o)),1)):E("",!0),ct(o)?(i(),c("div",Va,"下一次: "+v(ct(o)),1)):E("",!0),o.error?(i(),c("div",Ba,"错误: "+v(o.error),1)):E("",!0)]),l("div",Ha,[l("span",{class:pe(["status",ft(o)])},v(dt(o)),3),ht(o)?(i(),c("button",{key:0,type:"button",class:"download",onClick:h=>vt(o)},"下载",8,qa)):E("",!0),l("button",{type:"button",class:"btn-delete",onClick:h=>pt(o)},"删除",8,za)])]))),128))])])):E("",!0),De.value.length?(i(),c("div",ja,[t[23]||(t[23]=l("div",{class:"result-subsection-title"},"历史任务",-1)),l("ul",Ka,[(i(!0),c(V,null,j(De.value,o=>(i(),c("li",{key:`his-${o.resultId}-${o.taskId}`,class:"task-item"},[l("div",Ga,[l("span",{class:"id",title:o.shopName||""},v(o.shopName||"-"),9,Ja),l("div",Ya,"任务 ID: "+v(o.taskId??"-"),1),o.outputFilename?(i(),c("div",Qa,"文件: "+v(o.outputFilename),1)):E("",!0),o.error?(i(),c("div",Wa,"错误: "+v(o.error),1)):E("",!0)]),l("div",Xa,[l("span",{class:pe(["status",ft(o)])},v(dt(o)),3),ht(o)?(i(),c("button",{key:0,type:"button",class:"download",onClick:h=>vt(o)},"下载",8,Za)):E("",!0),l("button",{type:"button",class:"btn-delete",onClick:h=>pt(o)},"删除",8,en)])]))),128))])])):E("",!0)],64)):(i(),c("div",Pa,"暂无处理记录。推送队列并等待 Python 回传后,将在此显示下载链接。"))])])])])])}}}),sn=Vs(tn,[["__scopeId","data-v-9e4d7259"]]);Bs.locale("zh-cn");Hs(sn).use(qs,{locale:zs}).mount("#app"); +import{d as ds,g as m,o as fs,M as hs,a as i,c,b,B as vs,e as l,ad as ps,ae as ms,t as v,af as A,ag as gs,ah as ys,F as V,r as j,ai as St,n as pe,f as E,aj as Ss,ak as kt,al as ks,am as ws,w as _s,v as bs,aB as Ts,y as me,h as ge,aC as Cs,aD as Es,aE as Is,aF as Ds,E as p,aG as $s,aH as Ns,aI as Ms,aJ as Ps,s as xs,aK as As,aL as Ls,i as wt,aM as Fs,aN as Us,aO as Ue,aP as Rs,V as Os,_ as Vs,aQ as Bs,q as Hs,u as qs}from"./java-modules-B8c-YG5x.js";import{z as zs}from"./zh-cn-CscLo6na.js";/* empty css */import{L as js}from"./listingFilters-BpGOU_pJ.js";import{c as Ks}from"./categorized-timers-JPA-olTr.js";const Gs={class:"page-shell module-page"},Js={class:"main-content"},Ys={class:"left-panel"},Qs={class:"input-zone"},Ws={class:"input-row"},Xs=["disabled"],Zs={key:0,class:"empty-candidates"},ea={key:1,class:"candidate-table-scroll"},ta=["onClick"],sa={class:"country-pref-checks"},aa=["checked","disabled","onChange"],na={class:"country-check-text"},oa={key:2,class:"country-order-panel"},la={class:"country-order-list"},ra=["onDragstart","onDrop"],ua={class:"country-drag-label"},ia={key:3,class:"country-pref-status"},ca={class:"listing-filter-row"},da={class:"schedule-switch"},fa=["disabled"],ha={key:4,class:"schedule-config"},va=["disabled","onClick"],pa=["disabled"],ma={class:"run-row"},ga=["disabled"],ya=["disabled"],Sa={key:5,class:"queue-debug-card"},ka={class:"queue-debug-line"},wa={key:0,class:"queue-debug-payload"},_a={class:"right-panel"},ba={class:"task-list-wrap"},Ta={class:"clean-result-summary"},Ca={class:"summary-card"},Ea={class:"summary-card"},Ia={class:"summary-card"},Da={class:"summary-card"},$a={key:0,class:"empty-tasks narrow"},Na=["onClick"],Ma={class:"result-list-wrap"},Pa={key:0,class:"empty-tasks"},xa={key:0,class:"result-subsection"},Aa={class:"task-list"},La={class:"left split-result-main"},Fa=["title"],Ua={class:"files"},Ra={key:0,class:"files"},Oa={key:1,class:"files"},Va={key:2,class:"files"},Ba={key:3,class:"files"},Ha={class:"task-right"},qa=["onClick"],za=["onClick"],ja={key:1,class:"result-subsection"},Ka={class:"task-list"},Ga={class:"left split-result-main"},Ja=["title"],Ya={class:"files"},Qa={key:0,class:"files"},Wa={key:1,class:"files"},Xa={class:"task-right"},Za=["onClick"],en=["onClick"],tn=ds({__name:"BrandShopMatchTab",setup(an){const ye=[{code:"DE",label:"德国"},{code:"UK",label:"英国"},{code:"FR",label:"法国"},{code:"IT",label:"意大利"},{code:"ES",label:"西班牙"}],ae=m(""),Se=m([]),Re=m([]),T=m([]),ke=m("Active"),ne=m(!1),oe=m(!1),P=m(!1),we=m(!1),_e=m(!1),S=m(""),K=m(""),g=m(["DE","UK","FR","IT","ES"]),G=m(null),be=m(!1),Te=m(!1);let B=null;const x=m(!0),k=m([$e()]),J=m({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),D=m([]),y=m([]),w=m({}),d=m({}),M=m(null),Ce=m(!1),N=new Map,Ee=m(!1);let Y=null,Oe=0,Ve="",_=!1;const C=Ks("shop-match"),Ie=ge(()=>Je(D.value.filter(e=>!!I(e.taskId)&&!Xe(e)),d.value,"current")),De=ge(()=>Je(D.value.filter(e=>!I(e.taskId)||Xe(e)),d.value,"history")),_t=ge(()=>Ie.value.length>0||De.value.length>0),bt=ge(()=>{const e=new Set(g.value);return[...g.value.map(t=>({code:t,label:Ke(t)})),...ye.filter(t=>!e.has(t.code)).map(t=>({code:t.code,label:t.label}))]});function Q(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function Tt(){const e=Number(Q());return Number.isFinite(e)&&e>0?e:0}function I(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:0}function Be(){return`shop-match:tasks:${Q()}`}function He(){return`shop-match:task-status:${Q()}`}function qe(){return`shop-match:task-snapshots:${Q()}`}function ze(){return`shop-match:matched-items:${Q()}`}function le(e,t,s){s?window.localStorage.removeItem(e):window.localStorage.setItem(e,JSON.stringify(t))}function L(e){return`${(e.shopName||"").trim()}::${e.shopId||""}`}function je(e){return`${I(e.taskId)}-${e.resultId||0}-${e.shopName||""}`}function Ke(e){return ye.find(t=>t.code===e)?.label||e}function Ct(e){const t=e.getFullYear(),s=String(e.getMonth()+1).padStart(2,"0"),a=String(e.getDate()).padStart(2,"0"),n=String(e.getHours()).padStart(2,"0"),u=String(e.getMinutes()).padStart(2,"0"),r=String(e.getSeconds()).padStart(2,"0");return`${t}-${s}-${a}T${n}:${u}:${r}`}function re(e){const t=e.getFullYear(),s=String(e.getMonth()+1).padStart(2,"0"),a=String(e.getDate()).padStart(2,"0"),n=String(e.getHours()).padStart(2,"0"),u=String(e.getMinutes()).padStart(2,"0");return`${t}-${s}-${a} ${n}:${u}:00`}function $e(){const e=new Date;return e.setSeconds(0,0),e.setMinutes(e.getMinutes()+5),re(e)}function W(e){if(!e)return null;const s=e.trim().replace("T"," ").match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})(?::(\d{2}))?$/);if(!s)return null;const a=Number(s[1]),n=Number(s[2]),u=Number(s[3]),r=Number(s[4]),f=Number(s[5]),o=Number(s[6]||"0"),h=new Date(a,n-1,u,r,f,o,0);return Number.isNaN(h.getTime())||h.getFullYear()!==a||h.getMonth()!==n-1||h.getDate()!==u?null:h}function Et(e,t){const s=W(e)||new Date;return s.setSeconds(0,0),s.setMinutes(s.getMinutes()+t),re(s)}function Ge(e){const t=W(e);if(!t)return"-";const s=String(t.getMonth()+1).padStart(2,"0"),a=String(t.getDate()).padStart(2,"0"),n=String(t.getHours()).padStart(2,"0"),u=String(t.getMinutes()).padStart(2,"0");return`${s}-${a} ${n}:${u}`}function Je(e,t,s){const a=new Map;for(const n of e)a.set(je(n),n);for(const[n,u]of Object.entries(t)){const r=I(n),f=u.items?.[0];if(!f||!r)continue;const o=We(r);if(s==="current"&&o||s==="history"&&!o)continue;const h=je({...f,taskId:r});a.has(h)||a.set(h,{...f,taskId:r})}return Array.from(a.values())}function It(){try{const e=window.localStorage.getItem(Be()),t=e?JSON.parse(e):[];y.value=Array.isArray(t)?t.filter(s=>typeof s=="number"&&s>0):[]}catch{y.value=[]}}function ue(){le(Be(),y.value,y.value.length===0)}function Dt(){try{const e=window.localStorage.getItem(He());w.value=e?JSON.parse(e):{}}catch{w.value={}}}function F(){le(He(),w.value,Object.keys(w.value).length===0)}function $t(){try{const e=window.localStorage.getItem(qe());d.value=e?JSON.parse(e):{}}catch{d.value={}}}function H(){le(qe(),d.value,Object.keys(d.value).length===0)}function Nt(){try{const e=window.localStorage.getItem(ze());T.value=e?JSON.parse(e):[]}catch{T.value=[]}}function Ne(){le(ze(),T.value,T.value.length===0)}function Mt(e){const t=e instanceof Error?e.message:String(e||"");return/记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(t)}function Pt(){const e=y.value.filter(t=>(w.value[t]||d.value[t]?.task?.status)==="RUNNING");e.length!==y.value.length&&(y.value=e,ue())}function Ye(e){y.value.includes(e)||(y.value=[...y.value,e],ue())}function ie(e){const t=N.get(e);t&&(C.clearTimer("scheduled-dispatch",t),N.delete(e),N.size||fe())}function ce(e){if(ie(e),y.value=y.value.filter(t=>t!==e),delete w.value[e],d.value[e]){const t={...d.value};delete t[e],d.value=t,H()}ue(),F()}function X(e){ce(e),D.value=D.value.filter(t=>I(t.taskId)!==e)}function Qe(e,t=!0){y.value=y.value.filter(s=>s!==e),t||delete w.value[e],ue(),F()}function Z(e){return e==="SUCCESS"||e==="FAILED"||e==="COMPLETED"}function We(e){if(!e)return!1;const t=w.value[e]||d.value[e]?.task?.status;return Z(t)}function Xe(e){const t=I(e.taskId);return t&&We(t)||Z(e.taskStatus)?!0:!!e.success}async function ee(){Se.value=await Cs()}async function U(){J.value=await Es()}async function q(){const e=await Is();D.value=e.items||[]}async function xt(){try{const e=await Ds();if(Te.value)return;const t=(e.country_codes||[]).filter(s=>ye.some(a=>a.code===s));t.length&&(g.value=t)}catch{}}async function de(){await Promise.allSettled([q(),U()])}function Ze(){B&&C.clearTimer("preference-save",B),B=C.setTimeout("preference-save",()=>{B=null,At()},450)}async function At(){if(g.value.length){be.value=!0;try{await Us(g.value)}catch(e){p.error(e instanceof Error?e.message:"保存国家配置失败")}finally{be.value=!1}}}function Lt(e){Re.value=e}async function et(){const e=ae.value.trim();if(!e){p.warning("请输入店铺名");return}ne.value=!0;try{await $s(e),ae.value="",await ee(),await U()}catch(t){p.error(t instanceof Error?t.message:"添加失败")}finally{ne.value=!1}}async function Ft(e){try{await Ns(e.id),await ee(),await U()}catch(t){p.error(t instanceof Error?t.message:"删除失败")}}function Ut(e){return g.value.includes(e)}function tt(e){return g.value.length===1&&g.value[0]===e}function Rt(e,t){const s=t.target;if(s){if(!s.checked&&tt(e)){s.checked=!0,p.warning("至少保留 1 个国家");return}Ot(e,s.checked)}}function Ot(e,t){if(Te.value=!0,t)g.value.includes(e)||(g.value=[...g.value,e]);else{if(g.value.length<=1){p.warning("至少保留 1 个国家");return}g.value=g.value.filter(s=>s!==e)}Ze()}function Vt(e){G.value=e}function Bt(){G.value=null}function Ht(e){const t=G.value;if(G.value=null,t==null||t===e)return;Te.value=!0;const s=[...g.value],[a]=s.splice(t,1);s.splice(e,0,a),g.value=s,Ze()}function qt(){x.value&&(k.value=Me(k.value,!0)),x.value||(k.value=[])}function zt(){const e=k.value[k.value.length-1],t=e?Et(e,60):$e();k.value=[...k.value,t]}function jt(e){k.value.length<=1||(k.value=k.value.filter((t,s)=>s!==e))}function Kt(e,t){const s=[...k.value];s[e]=t||"",k.value=Me(s,!1)}function Gt(e,t){const s=new Map;for(const a of e)s.set(L(a),a);for(const a of t)s.set(L(a),a);return Array.from(s.values())}async function Jt(){const e=Re.value.map(t=>t.shop_name).filter(Boolean);if(!e.length){p.warning("请先选择候选店铺");return}oe.value=!0;try{const t=await Ms(e);T.value=Gt(T.value,t.items||[]),Ne(),_e.value&&mt(),p.success(`本次返回 ${t.items?.length||0} 条匹配结果`)}catch(t){p.error(t instanceof Error?t.message:"匹配失败")}finally{oe.value=!1}}function Yt(e){T.value=T.value.filter(t=>L(t)!==L(e)),Ne()}function R(e){const t=new Set(e.map(s=>L(s)));T.value=T.value.filter(s=>!t.has(L(s))),Ne()}function Qt(){if(!x.value)return;const e=Date.now(),t=k.value.map(n=>n.trim()).filter(Boolean);if(!t.length)throw new Error("请至少选择一个执行时间");const s=t.map(n=>{const u=W(n);if(!u)throw new Error(`时间格式无效: ${n}`);return{raw:Ct(u),picker:re(u),time:u.getTime()}}).sort((n,u)=>n.time-u.time);for(let n=1;nn.time>e);if(!a.length)throw new Error("执行时间必须晚于当前时间,请重新选择");return a.length!==s.length&&(k.value=a.map(n=>n.picker),p.warning("已自动移除早于当前时间的执行时间")),a.map(n=>n.raw)}function Me(e,t){const s=Date.now(),a=e.map(r=>r.trim()).filter(Boolean).map(r=>{const f=W(r);return f?{value:re(f),time:f.getTime()}:null}).filter(r=>!!r).filter(r=>r.time>s).sort((r,f)=>r.time-f.time),n=[],u=new Set;for(const r of a)u.has(r.value)||(u.add(r.value),n.push(r.value));return!n.length&&t?[$e()]:n}function Wt(e){return e.skipAsinsByCountry||e.skip_asins_by_country||{}}function Xt(e){return e.skipAsinDetailsByCountry||e.skip_asin_details_by_country||{}}function st(e,t,s,a,n=!0){const u=Wt(t),r=Xt(t);return{type:"shop-match-run",ts:Date.now(),data:{taskId:e,user_id:Tt(),items:[{shopName:t.shopName,shopId:t.shopId,platform:t.platform,companyName:t.companyName,matched:!0,matchStatus:t.matchStatus,matchMessage:t.matchMessage,skip_asins_by_country:u,skipAsinsByCountry:u,skip_asin_details_by_country:r,skipAsinDetailsByCountry:r}],country_codes:[...s],skip_asins_by_country:u,skipAsinsByCountry:u,skip_asin_details_by_country:r,skipAsinDetailsByCountry:r,risk_listing_filter:ke.value,stage_index:a,final_stage:n}}}function Pe(e){const t=d.value[e]?.task,s=t?.scheduleStages||[],a=t?.currentStageIndex;if(typeof a!="number")return null;const n=s.find(u=>u.stageIndex===a);return n?.scheduledAt?{stageIndex:a,scheduledAt:n.scheduledAt,finalStage:a===s.length-1}:null}async function Zt(e,t){const s=wt();if(!s?.enqueue_json)throw new Error("当前客户端未提供 enqueue_json");const a=Pe(e),n=d.value[e],u=n?.task?.countryCodes||g.value;if(!a)throw new Error(`任务 ${e} 缺少待执行阶段`);ie(e),await ot(()=>Rs(e,a.stageIndex),(o,h)=>{S.value=`任务 ${e} 等待后端恢复后再激活执行(${o}/${h})...`}),w.value={...w.value,[e]:"RUNNING"},n?.task&&(d.value={...d.value,[e]:{...n,task:{...n.task,status:"RUNNING",activeStageIndex:a.stageIndex}}}),H(),F();const r=st(e,t,u,a.stageIndex,a.finalStage);K.value=JSON.stringify(r,null,2);const f=await s.enqueue_json(r);if(!f?.success)throw new Error(f?.error||`任务 ${e} 推送失败`);Ye(e),S.value=`任务 ${e} 已推送第 ${a.stageIndex+1} 轮`,se(!0)}function at(e){const t=W(e);return t?t.getTime():Number.NaN}function es(){const e=new Set(y.value);for(const s of Object.keys(d.value)){const a=I(s);a>0&&e.add(a)}for(const s of D.value){const a=I(s.taskId);a>0&&e.add(a)}const t=Array.from(e).map(s=>{const a=d.value[s],n=w.value[s]||a?.task?.status,u=a?.items?.[0]||D.value.find(o=>I(o.taskId)===s),r=Pe(s);if(n!=="SCHEDULED"||!u||!r?.scheduledAt)return null;const f=at(r.scheduledAt);return!Number.isFinite(f)||f>Date.now()?null:{taskId:s,item:u,scheduledTime:f}}).filter(s=>!!s);return t.sort((s,a)=>s.scheduledTime-a.scheduledTime||s.taskId-a.taskId),t}async function xe(){if(Ee.value)return;const e=es();if(e.length){Ee.value=!0;try{const t=e[0];try{await Zt(t.taskId,t.item),await ls(t.taskId)}catch(s){const a=s instanceof Error?s.message:`任务 ${t.taskId} 调度失败`,n=`${t.taskId}:${a}`,u=Date.now();S.value=a,(Ve!==n||u-Oe>1e4)&&(Ve=n,Oe=u,p.error(a)),await Promise.allSettled([q(),lt()])}}finally{Ee.value=!1,$()}}}function ts(e,t){if(_||!t)return;ie(e);const s=at(t);if(!Number.isFinite(s))return;const a=Math.max(0,s-Date.now()),n=C.setTimeout("scheduled-dispatch",()=>{N.delete(e),N.size||fe(),_||xe()},a);N.set(e,n),nt()}function $(){if(_)return;const e=new Set(y.value);for(const t of Object.keys(d.value)){const s=I(t);s>0&&e.add(s)}for(const t of D.value){const s=I(t.taskId);s>0&&e.add(s)}for(const t of e){const a=d.value[t]?.task?.status||w.value[t],n=Pe(t);a==="SCHEDULED"&&n?.scheduledAt?ts(t,n.scheduledAt):ie(t)}N.size?nt():fe(),xe()}function nt(){_||Y||!N.size||(Y=C.setInterval("schedule-heartbeat",()=>{_||xe()},3e4))}function fe(){Y&&(C.clearTimer("schedule-heartbeat",Y),Y=null)}function he(){$(),y.value.length&&se(!0)}const ss=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"];function te(e){return _?Promise.resolve():C.sleep("queue-wait",e)}function as(){C.clearCategory("queue-wait")}function Ae(e){const t=(e instanceof Error?e.message:String(e||"")).toLowerCase();return ss.some(s=>t.includes(s.toLowerCase()))}async function ot(e,t,s=10){let a=0;for(;;){if(_)throw new Error("component disposed");try{return await e()}catch(n){if(a+=1,!Ae(n)||a>=s)throw n;t(a,s),await te(O())}}}async function lt(){if(!y.value.length)return{settledTaskIds:[]};try{const e=await Ue(y.value),t={...d.value},s=new Set;for(const a of e.missingTaskIds||[])X(a),delete t[a],s.add(a);for(const a of e.items||[]){const n=a.task?.id;if(!n)continue;const u=t[n];t[n]=u?{...u,task:{...u.task||{},...a.task||{}}}:a;const r=a.task?.status||"";if(r){if(w.value[n]=r,Z(r)){ce(n),s.add(n);continue}r==="SCHEDULED"&&(Qe(n),s.add(n))}}return d.value=t,H(),F(),$(),{settledTaskIds:Array.from(s)}}catch{return{settledTaskIds:[]}}}function O(){return Os()}function rt(e=!1){if(_)return;if(M.value){if(!e)return;C.clearTimer("task-poll",M.value),M.value=null}const t=async()=>{if(M.value=null,!_){if(Ce.value||!y.value.length){y.value.length&&rt();return}Ce.value=!0;try{const{settledTaskIds:s}=await lt();s.length&&await Promise.allSettled([q(),U()])}finally{Ce.value=!1}!_&&y.value.length&&(M.value=C.setTimeout("task-poll",t,O()))}};e?t():M.value=C.setTimeout("task-poll",t,O())}function se(e=!1){rt(e)}function ns(){M.value&&(C.clearTimer("task-poll",M.value),M.value=null)}async function os(e){let t=0;const s=30;for(;;){if(_)return"STOPPED";try{const a=await Ue([e]);if(t>0&&(S.value=`任务 ${e} 后端已恢复,继续等待执行结果...`),t=0,(a.missingTaskIds||[]).includes(e))return X(e),await de(),$(),"FAILED";const n=(a.items||[]).find(r=>r.task?.id===e),u=n?.task?.status||"";if(n){const r=d.value[e];d.value={...d.value,[e]:r?{...r,task:{...r.task||{},...n.task||{}}}:n},H()}if(u&&(w.value[e]=u,F()),Z(u))return ce(e),await de(),$(),u}catch(a){if(!Ae(a))throw a;if(t+=1,t>=s)throw new Error(`任务 ${e} 等待后端恢复超时,请稍后手动刷新查看状态`);S.value=`任务 ${e} 运行中,正在等待后端服务恢复(${t}/${s})...`,(t===1||t%5===0)&&p.warning(`任务 ${e} 运行中,后端服务暂时不可用,正在自动重试`),await te(O());continue}await te(O())}}async function ls(e){let t=0;const s=30;for(;;){if(_)return"STOPPED";try{const a=await Ue([e]);if(t>0&&(S.value=`任务 ${e} 后端已恢复,继续等待当前轮次结束...`),t=0,(a.missingTaskIds||[]).includes(e))return X(e),await de(),$(),"FAILED";const n=(a.items||[]).find(r=>r.task?.id===e),u=n?.task?.status||"";if(n){const r=d.value[e];d.value={...d.value,[e]:r?{...r,task:{...r.task||{},...n.task||{}}}:n},H()}if(u&&(w.value[e]=u,F()),!u||u==="RUNNING"){await te(O());continue}return Z(u)?(ce(e),await de(),$(),u):(u==="SCHEDULED"&&(Qe(e),$()),u)}catch(a){if(!Ae(a))throw a;if(t+=1,t>=s)throw new Error(`任务 ${e} 等待当前轮次结束超时,请稍后手动刷新查看状态`);S.value=`任务 ${e} 运行中,正在等待当前轮次结束(${t}/${s})...`,(t===1||t%5===0)&&p.warning(`任务 ${e} 运行中,后端服务暂时不可用,正在自动重试`),await te(O())}}}function Le(e){const t=I(e.taskId);return t?w.value[t]||d.value[t]?.task?.status||e.taskStatus||"":e.taskStatus||""}function ut(e){const t=I(e.taskId);return t?d.value[t]:void 0}function it(e){const s=ut(e)?.task,a=s?.scheduleStages||[];if(!a.length)return"";const n=a.length,u=typeof s?.activeStageIndex=="number"?s.activeStageIndex:void 0,r=typeof s?.currentStageIndex=="number"?s.currentStageIndex:void 0;return typeof u=="number"?`执行进度: 第 ${u+1}/${n} 次执行中`:typeof r=="number"?`执行进度: 等待第 ${r+1}/${n} 次`:`执行进度: 共 ${n} 次`}function ct(e){const s=ut(e)?.task,a=s?.scheduleStages||[];if(typeof s?.currentStageIndex=="number"){const n=a.find(u=>u.stageIndex===s.currentStageIndex);if(n?.scheduledAt)return Ge(n.scheduledAt)}return e.scheduledAt?Ge(e.scheduledAt):""}function dt(e){const t=Le(e);return t==="SCHEDULED"?"待执行":t==="RUNNING"?"执行中":t==="SUCCESS"||t==="COMPLETED"?"已完成":t==="FAILED"?"失败":e.success?"已完成":"未知"}function ft(e){const t=Le(e);return t==="SUCCESS"||t==="COMPLETED"?"success":t==="FAILED"?"failed":"running"}function ht(e){const t=Le(e);return!!e.resultId&&(!!e.fileReady||!!e.downloadUrl)&&(t==="SUCCESS"||t==="COMPLETED")}async function vt(e){if(!e.resultId)return;const t=Ps(e.resultId),s=e.outputFilename||`${e.shopName||"result"}.xlsx`,a=await xs(t,s,`shop-match:${e.resultId}`);a.success?p.success(`已保存: ${a.path||s}`):a.error&&a.error!=="用户取消"&&p.error(a.error)}async function pt(e){const t=I(e.taskId),s=Number(e.resultId||0);try{if(t>0)await As(t),X(t);else if(s>0)await Ls(s),D.value=D.value.filter(a=>Number(a.resultId||0)!==s),R([e]);else throw new Error("缺少可删除的任务标识");await Promise.allSettled([q(),ee(),U()]),p.success("删除成功")}catch(a){if(Mt(a)){t>0?X(t):s>0&&(D.value=D.value.filter(n=>Number(n.resultId||0)!==s)),R([e]),await Promise.allSettled([q(),ee(),U()]),p.success("后端记录已不存在,本地记录已同步清理");return}p.error(a instanceof Error?a.message:"删除失败")}}function rs(e){const t=(e||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[t]||t||"—"}function us(e){const t=(e.matchMessage||"").trim();return t||(e.matched&&e.matchStatus==="MATCHED"?"紫鸟索引已命中,可推送队列":e.matched?"已关联索引,请结合状态列查看是否可推送":"未命中或未就绪,请检查店铺名与索引刷新")}async function is(){_e.value=!0,await mt()}function cs(){return T.value.find(e=>e.matched)}async function mt(){if(_||we.value)return;const e=wt();if(!e?.enqueue_json){p.error("当前客户端未提供 enqueue_json");return}if(!T.value.filter(r=>r.matched).length){p.warning("请先匹配可用店铺");return}if(!g.value.length){p.warning("请至少勾选一个国家");return}let s;try{s=Qt()}catch(r){p.error(r instanceof Error?r.message:"定时配置无效");return}we.value=!0,P.value=!0,K.value="";let a=0,n=0,u=0;try{for(;!_&&_e.value;){const r=cs();if(!r)break;u+=1;try{const f=await ot(()=>Fs([r],g.value,s),(Fe,ve)=>{S.value=`后端服务暂时不可用,正在重试创建任务(${Fe}/${ve})...`}),o=f.taskId,h=s?.length?"SCHEDULED":"RUNNING",z={task:{id:o,status:h,scheduledAt:s?.[0],countryCodes:[...g.value],currentStageIndex:s?.length?0:void 0,activeStageIndex:void 0,scheduleStages:(s||[]).map((Fe,ve)=>({stageIndex:ve,scheduledAt:Fe,status:ve===0?"SCHEDULED":"PENDING"}))},items:f.items};if(d.value={...d.value,[o]:z},w.value={...w.value,[o]:h},H(),F(),!f.items?.[0]){R([r]);continue}if(s?.length){a+=1,$(),S.value=`任务 ${o} 已创建,共 ${s.length} 个执行时间点`,R([r]);continue}const gt=st(o,r,g.value);K.value=JSON.stringify(gt,null,2);const yt=await e.enqueue_json(gt);if(!yt?.success){n+=1,S.value=`任务 ${o} 推送失败,已自动继续下一条:${yt?.error||"未知错误"}`,p.error(S.value),R([r]);continue}if(Ye(o),se(!0),R([r]),S.value=`任务 ${o} 已入队,等待执行完成`,await os(o)!=="SUCCESS"){n+=1,S.value=`任务 ${o} 执行失败,已自动继续下一条`,p.error(S.value);continue}a+=1,S.value=`任务 ${o} 已完成`}catch(f){if(_)break;n+=1,S.value=`第 ${u} 条任务处理失败,已自动继续下一条:${f instanceof Error?f.message:"未知错误"}`,p.error(S.value),R([r]);continue}}$(),s?.length||se(!0),!_&&(a>0||n>0)&&p.success(s?.length?`定时任务已创建:成功 ${a} 条,失败 ${n} 条`:`店铺推送已完成:成功 ${a} 条,失败 ${n} 条`)}catch(r){if(_)return;const f=r instanceof Error?r.message:"推送失败";S.value=f,p.error(f)}finally{we.value=!1,P.value=!1}}return fs(async()=>{It(),Dt(),$t(),Nt(),k.value=Me(k.value,x.value),Pt(),await Promise.allSettled([ee(),xt(),q(),U()]),window.addEventListener("focus",he),document.addEventListener("visibilitychange",he),$(),y.value.length&&se(!0)}),hs(()=>{_=!0,ns(),fe(),as(),window.removeEventListener("focus",he),document.removeEventListener("visibilitychange",he),B&&C.clearTimer("preference-save",B);for(const e of N.values())C.clearTimer("scheduled-dispatch",e);N.clear(),C.clearScope()}),(e,t)=>{const s=ms,a=gs,n=ys,u=ks,r=ws,f=Ts;return i(),c("div",Gs,[b(vs,{active:"shop-match"}),l("div",Js,[l("aside",Ys,[t[10]||(t[10]=l("div",{class:"section-title"},"店铺候选",-1)),l("div",Qs,[t[4]||(t[4]=l("div",{class:"hint"},"输入店铺名后点“添加”加入下方备选区。勾选备选店铺后先做“匹配店铺”,确认命中紫鸟索引后再推送到 Python 队列。",-1)),l("div",Ws,[b(s,{modelValue:ae.value,"onUpdate:modelValue":t[0]||(t[0]=o=>ae.value=o),clearable:"",placeholder:"请输入店铺名后回车或点击添加",onKeyup:ps(et,["enter"])},null,8,["modelValue"]),l("button",{type:"button",class:"opt-btn",disabled:ne.value,onClick:et},v(ne.value?"添加中...":"添加"),9,Xs)])]),t[11]||(t[11]=l("div",{class:"section-title"},"备选店铺",-1)),Se.value.length?(i(),c("div",ea,[b(n,{data:Se.value,"row-key":"id",height:"240",class:"candidate-table",onSelectionChange:Lt},{default:A(()=>[b(a,{type:"selection",width:"42"}),b(a,{prop:"shop_name",label:"店铺名","min-width":"120","show-overflow-tooltip":""}),b(a,{label:"操作",width:"72",align:"center"},{default:A(({row:o})=>[l("button",{type:"button",class:"link-danger",onClick:h=>Ft(o)},"删除",8,ta)]),_:1})]),_:1},8,["data"])])):(i(),c("div",Zs,"暂无备选店铺,请先输入并添加")),t[12]||(t[12]=l("div",{class:"section-title"},"国家配置",-1)),t[13]||(t[13]=l("p",{class:"hint country-pref-hint"},"勾选的国家会在每一个执行时间点都执行一遍。勾选区会按照已选顺序排在前面,下方支持拖拽排序,和商品风险页保持一致。",-1)),l("div",sa,[(i(!0),c(V,null,j(bt.value,o=>(i(),c("label",{key:o.code,class:"country-check-row"},[l("input",{type:"checkbox",class:"country-check-input",checked:Ut(o.code),disabled:tt(o.code),onChange:h=>Rt(o.code,h)},null,40,aa),l("span",na,v(o.label)+" ("+v(o.code)+")",1)]))),128))]),g.value.length?(i(),c("div",oa,[t[6]||(t[6]=l("div",{class:"country-order-caption"},"已选顺序(拖拽 ⋮⋮ 调整)",-1)),l("div",la,[(i(!0),c(V,null,j(g.value,(o,h)=>(i(),c("div",{key:o,class:pe(["country-drag-row",{dragging:G.value===h}]),draggable:"true",onDragstart:z=>Vt(h),onDragend:Bt,onDragover:t[1]||(t[1]=St(()=>{},["prevent"])),onDrop:St(z=>Ht(h),["prevent"])},[t[5]||(t[5]=l("span",{class:"drag-handle",title:"拖动排序"},"⋮⋮",-1)),l("span",ua,v(Ke(o))+" ("+v(o)+")",1)],42,ra))),128))])])):E("",!0),be.value?(i(),c("div",ia,"保存中...")):E("",!0),t[14]||(t[14]=l("div",{class:"section-title"},"商品列表筛选",-1)),t[15]||(t[15]=l("p",{class:"hint listing-filter-hint"},"与“推送到 Python 队列”一并下发,供 Python 区分处理场景。",-1)),l("div",ca,[b(r,{modelValue:ke.value,"onUpdate:modelValue":t[2]||(t[2]=o=>ke.value=o),class:"listing-filter-select",teleported:"",placeholder:"选择筛选类型"},{default:A(()=>[(i(!0),c(V,null,j(Ss(js),o=>(i(),kt(u,{key:o.value,label:o.label,value:o.value},null,8,["label","value"]))),128))]),_:1},8,["modelValue"])]),t[16]||(t[16]=l("div",{class:"section-title"},"定时执行",-1)),l("label",da,[_s(l("input",{"onUpdate:modelValue":t[3]||(t[3]=o=>x.value=o),type:"checkbox",disabled:P.value,onChange:qt},null,40,fa),[[bs,x.value]]),t[7]||(t[7]=l("span",null,"启用多时间点调度",-1))]),x.value?(i(),c("div",ha,[(i(!0),c(V,null,j(k.value,(o,h)=>(i(),c("div",{key:`schedule-${h}`,class:"schedule-row"},[b(f,{"model-value":o,type:"datetime","value-format":"YYYY-MM-DD HH:mm:ss",format:"MM-DD HH:mm",placeholder:"选择执行时间",disabled:P.value,class:"schedule-picker","onUpdate:modelValue":z=>Kt(h,z)},null,8,["model-value","disabled","onUpdate:modelValue"]),l("button",{type:"button",class:"schedule-remove",disabled:P.value||k.value.length<=1,onClick:z=>jt(h)},"删除",8,va)]))),128)),l("button",{type:"button",class:"schedule-add",disabled:P.value,onClick:zt},"添加时间点",8,pa),t[8]||(t[8]=l("p",{class:"hint schedule-hint"},"默认开启定时;支持按 `MM-DD HH:mm` 配置多个时间点,前端不再限制选择更早时间,实际是否可执行以后端校验为准。",-1))])):E("",!0),l("div",ma,[l("button",{type:"button",class:"btn-run",disabled:oe.value,onClick:Jt},v(oe.value?"匹配中...":"匹配店铺"),9,ga),l("button",{type:"button",class:"btn-run btn-queue",disabled:P.value||!T.value.length,onClick:is},v(P.value?"推送中...":x.value?"创建定时任务":"推送到 Python 队列"),9,ya)]),t[17]||(t[17]=l("p",{class:"loading-msg"},[me("已支持多阶段定时执行;Python 每处理完一店可回传 "),l("code",null,"/api/shop-match/tasks/{taskId}/result"),me(",后端会按阶段汇总并在超时场景自动收尾。")],-1)),S.value?(i(),c("div",Sa,[t[9]||(t[9]=l("div",{class:"section-title queue-debug-title"},"推送结果",-1)),l("div",ka,v(S.value),1),K.value?(i(),c("pre",wa,v(K.value),1)):E("",!0)])):E("",!0)]),l("section",_a,[t[26]||(t[26]=l("div",{class:"panel-header"},"匹配与任务",-1)),l("div",ba,[l("div",Ta,[l("div",Ca,[t[18]||(t[18]=l("span",{class:"summary-label"},"候选店铺",-1)),l("strong",null,v(J.value.candidateCount),1)]),l("div",Ea,[t[19]||(t[19]=l("span",{class:"summary-label"},"已结束任务",-1)),l("strong",null,v(J.value.processedTaskCount),1)]),l("div",Ia,[t[20]||(t[20]=l("span",{class:"summary-label"},"成功",-1)),l("strong",null,v(J.value.successTaskCount),1)]),l("div",Da,[t[21]||(t[21]=l("span",{class:"summary-label"},"失败",-1)),l("strong",null,v(J.value.failedTaskCount),1)])]),t[25]||(t[25]=l("div",{class:"subsection-title"},"匹配结果",-1)),T.value.length?(i(),kt(n,{key:1,data:T.value,"row-key":L,"highlight-current-row":!1,class:"result-table match-table"},{default:A(()=>[b(a,{prop:"shopName",label:"店铺名","min-width":"100"}),b(a,{label:"匹配",width:"72",align:"center"},{default:A(({row:o})=>[l("span",{class:pe(o.matched?"ok":"fail")},v(o.matched?"是":"否"),3)]),_:1}),b(a,{prop:"shopId",label:"店铺ID","min-width":"120","show-overflow-tooltip":""}),b(a,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),b(a,{prop:"companyName",label:"公司","min-width":"100","show-overflow-tooltip":""}),b(a,{label:"状态",width:"100","show-overflow-tooltip":""},{default:A(({row:o})=>[me(v(rs(o.matchStatus)),1)]),_:1}),b(a,{label:"说明","min-width":"140","show-overflow-tooltip":""},{default:A(({row:o})=>[me(v(us(o)),1)]),_:1}),b(a,{label:"操作",width:"72",align:"center"},{default:A(({row:o})=>[l("button",{type:"button",class:"link-danger",onClick:h=>Yt(o)},"删除",8,Na)]),_:1})]),_:1},8,["data"])):(i(),c("div",$a,"完成“匹配店铺”后,在此展示紫鸟索引匹配结果,供核对后再推送队列。")),l("div",Ma,[t[24]||(t[24]=l("div",{class:"result-list-header"},[l("span",null,"处理记录")],-1)),_t.value?(i(),c(V,{key:1},[Ie.value.length?(i(),c("div",xa,[t[22]||(t[22]=l("div",{class:"result-subsection-title"},"当前任务",-1)),l("ul",Aa,[(i(!0),c(V,null,j(Ie.value,o=>(i(),c("li",{key:`cur-${o.resultId}-${o.taskId}`,class:"task-item"},[l("div",La,[l("span",{class:"id",title:o.shopName||""},v(o.shopName||"-"),9,Fa),l("div",Ua,"任务 ID: "+v(o.taskId??"-"),1),o.platform?(i(),c("div",Ra,"平台: "+v(o.platform),1)):E("",!0),it(o)?(i(),c("div",Oa,v(it(o)),1)):E("",!0),ct(o)?(i(),c("div",Va,"下一次: "+v(ct(o)),1)):E("",!0),o.error?(i(),c("div",Ba,"错误: "+v(o.error),1)):E("",!0)]),l("div",Ha,[l("span",{class:pe(["status",ft(o)])},v(dt(o)),3),ht(o)?(i(),c("button",{key:0,type:"button",class:"download",onClick:h=>vt(o)},"下载",8,qa)):E("",!0),l("button",{type:"button",class:"btn-delete",onClick:h=>pt(o)},"删除",8,za)])]))),128))])])):E("",!0),De.value.length?(i(),c("div",ja,[t[23]||(t[23]=l("div",{class:"result-subsection-title"},"历史任务",-1)),l("ul",Ka,[(i(!0),c(V,null,j(De.value,o=>(i(),c("li",{key:`his-${o.resultId}-${o.taskId}`,class:"task-item"},[l("div",Ga,[l("span",{class:"id",title:o.shopName||""},v(o.shopName||"-"),9,Ja),l("div",Ya,"任务 ID: "+v(o.taskId??"-"),1),o.outputFilename?(i(),c("div",Qa,"文件: "+v(o.outputFilename),1)):E("",!0),o.error?(i(),c("div",Wa,"错误: "+v(o.error),1)):E("",!0)]),l("div",Xa,[l("span",{class:pe(["status",ft(o)])},v(dt(o)),3),ht(o)?(i(),c("button",{key:0,type:"button",class:"download",onClick:h=>vt(o)},"下载",8,Za)):E("",!0),l("button",{type:"button",class:"btn-delete",onClick:h=>pt(o)},"删除",8,en)])]))),128))])])):E("",!0)],64)):(i(),c("div",Pa,"暂无处理记录。推送队列并等待 Python 回传后,将在此显示下载链接。"))])])])])])}}}),sn=Vs(tn,[["__scopeId","data-v-9e4d7259"]]);Bs.locale("zh-cn");Hs(sn).use(qs,{locale:zs}).mount("#app"); diff --git a/app/assets/similar-asin-Bl4LsbT8.css b/app/assets/similar-asin-Bl4LsbT8.css new file mode 100644 index 0000000..f51cc5d --- /dev/null +++ b/app/assets/similar-asin-Bl4LsbT8.css @@ -0,0 +1 @@ +.module-page[data-v-4ed8ec44]{min-height:100vh;background:#1a1a1a}.main-content[data-v-4ed8ec44]{display:flex;height:calc(100vh - 56px);min-height:calc(100vh - 56px)}.left-panel[data-v-4ed8ec44]{width:400px;background:#1e1e1e;padding:20px;overflow-y:auto;border-right:1px solid #2a2a2a}.right-panel[data-v-4ed8ec44]{flex:1;min-width:0;background:#1a1a1a;display:flex;flex-direction:column}.section-title[data-v-4ed8ec44],.subsection-title[data-v-4ed8ec44]{font-size:13px;color:#bbb;margin-bottom:10px}.upload-zone[data-v-4ed8ec44]{border:1px dashed #3a3a3a;border-radius:10px;padding:18px;background:#252525;margin-bottom:18px}.condition-card[data-v-4ed8ec44]{margin-bottom:18px;padding:14px 16px;border:1px solid #2f3a34;border-radius:10px;background:linear-gradient(135deg,#222a25,#202020)}.switch-row[data-v-4ed8ec44]{display:flex;align-items:center;justify-content:space-between;gap:14px;color:#d8e4dc;cursor:pointer;-webkit-user-select:none;user-select:none}.switch-row span[data-v-4ed8ec44]{display:flex;flex-direction:column;gap:4px;min-width:0}.switch-row strong[data-v-4ed8ec44]{font-size:13px;font-weight:600}.switch-row em[data-v-4ed8ec44]{color:#8d9a91;font-size:12px;font-style:normal;line-height:1.4}.switch-row input[data-v-4ed8ec44]{position:absolute;opacity:0;pointer-events:none}.switch-row i[data-v-4ed8ec44]{position:relative;width:46px;height:24px;flex:0 0 auto;border-radius:999px;background:#3a3a3a;box-shadow:inset 0 0 0 1px #4b4b4b;transition:background .2s ease,box-shadow .2s ease}.switch-row i[data-v-4ed8ec44]:after{content:"";position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:#c7c7c7;transition:transform .2s ease,background .2s ease}.switch-row input:checked+i[data-v-4ed8ec44]{background:#27ae60;box-shadow:inset 0 0 0 1px #42d17a}.switch-row input:checked+i[data-v-4ed8ec44]:after{transform:translate(22px);background:#fff}.hint[data-v-4ed8ec44],.loading-msg[data-v-4ed8ec44],.files[data-v-4ed8ec44],.muted[data-v-4ed8ec44]{color:#888;font-size:12px;line-height:1.5}.link[data-v-4ed8ec44]{color:#6ea8fe;text-decoration:none}.link[data-v-4ed8ec44]:hover{color:#9fc5ff}.btns[data-v-4ed8ec44],.run-row[data-v-4ed8ec44]{display:flex;gap:10px;flex-wrap:wrap}.opt-btn[data-v-4ed8ec44],.btn-run[data-v-4ed8ec44],.btn-delete[data-v-4ed8ec44],.download[data-v-4ed8ec44]{border:none;cursor:pointer;border-radius:7px}.opt-btn[data-v-4ed8ec44]{padding:8px 14px;color:#ccc;background:#2a2a2a;border:1px solid #3a3a3a}.btn-run[data-v-4ed8ec44]{padding:10px 18px;color:#fff;background:#3498db;font-weight:600}.btn-queue[data-v-4ed8ec44]{background:#27ae60}.btn-run[data-v-4ed8ec44]:disabled{opacity:.55;cursor:not-allowed}.selected-files[data-v-4ed8ec44]{margin-top:14px;color:#999;font-size:12px;word-break:break-all}.selected-files span[data-v-4ed8ec44]{display:block;margin:4px 0}.parse-card[data-v-4ed8ec44],.queue-payload[data-v-4ed8ec44]{margin-top:14px;padding:12px;border:1px solid #2a2a2a;border-radius:8px;background:#202020;color:#b8c1cc;font-size:12px}.queue-payload[data-v-4ed8ec44]{max-height:220px;overflow:auto;color:#8fd3ff;white-space:pre-wrap}.panel-header[data-v-4ed8ec44]{padding:16px 20px;border-bottom:1px solid #2a2a2a;font-size:15px;font-weight:600;color:#ddd}.task-list-wrap[data-v-4ed8ec44]{flex:1;padding:16px 20px;overflow:auto}.clean-result-summary[data-v-4ed8ec44]{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin-bottom:16px}.summary-card[data-v-4ed8ec44]{padding:14px 16px;border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e}.summary-card strong[data-v-4ed8ec44]{display:block;margin-top:8px;color:#eaf4ff;font-size:22px}.summary-label[data-v-4ed8ec44]{color:#8d8d8d;font-size:12px}.result-list-wrap[data-v-4ed8ec44]{border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e;min-height:180px;margin:0 0 16px}.result-list-header[data-v-4ed8ec44]{display:flex;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #2a2a2a;color:#ddd;font-size:14px}.empty-tasks[data-v-4ed8ec44]{color:#666;font-size:13px;padding:18px;text-align:center}.task-list[data-v-4ed8ec44]{list-style:none;margin:0;padding:12px}.task-item[data-v-4ed8ec44]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:12px 14px;border:1px solid #2a2a2a;border-radius:8px;margin-bottom:8px;background:#222}.left[data-v-4ed8ec44]{flex:1;min-width:0}.id[data-v-4ed8ec44]{color:#e0e0e0;font-size:13px;font-weight:600}.task-right[data-v-4ed8ec44]{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.status[data-v-4ed8ec44]{padding:4px 10px;border-radius:6px;font-size:12px}.status.success[data-v-4ed8ec44]{background:#2ecc712e;color:#2ecc71}.status.failed[data-v-4ed8ec44]{background:#e74c3c2e;color:#ff6b6b}.status.running[data-v-4ed8ec44]{background:#3498db2e;color:#3498db}.status.pending[data-v-4ed8ec44]{background:#95a5a62e;color:#bdc3c7}.result-hint[data-v-4ed8ec44]{margin-top:6px;color:#e0b96d}.file-progress[data-v-4ed8ec44]{margin-top:8px;max-width:520px}.file-progress-meta[data-v-4ed8ec44]{display:flex;justify-content:space-between;gap:12px;color:#d8c278;font-size:12px}.file-progress-track[data-v-4ed8ec44]{margin-top:5px;height:8px;border-radius:999px;overflow:hidden;background:#303030;border:1px solid #3b3b3b}.file-progress-bar[data-v-4ed8ec44]{height:100%;border-radius:inherit;background:linear-gradient(90deg,#4aa3ff,#f0c75e);transition:width .25s ease}.file-progress-count[data-v-4ed8ec44]{margin-top:4px;color:#858585;font-size:11px}.download[data-v-4ed8ec44]{padding:6px 10px;color:#d6ecff;background:#3498db2e}.btn-delete[data-v-4ed8ec44]{padding:6px 10px;color:#ff8f8f;background:#e74c3c1f}@media(max-width:1100px){.main-content[data-v-4ed8ec44]{flex-direction:column;height:auto}.left-panel[data-v-4ed8ec44]{width:100%;border-right:none;border-bottom:1px solid #2a2a2a}.clean-result-summary[data-v-4ed8ec44]{grid-template-columns:repeat(2,minmax(0,1fr))}} diff --git a/app/assets/similar-asin-CVYG_iIM.css b/app/assets/similar-asin-CVYG_iIM.css deleted file mode 100644 index a9ebc61..0000000 --- a/app/assets/similar-asin-CVYG_iIM.css +++ /dev/null @@ -1 +0,0 @@ -.module-page[data-v-39de0e76]{min-height:100vh;background:#1a1a1a}.main-content[data-v-39de0e76]{display:flex;height:calc(100vh - 56px);min-height:calc(100vh - 56px)}.left-panel[data-v-39de0e76]{width:400px;background:#1e1e1e;padding:20px;overflow-y:auto;border-right:1px solid #2a2a2a}.right-panel[data-v-39de0e76]{flex:1;min-width:0;background:#1a1a1a;display:flex;flex-direction:column}.section-title[data-v-39de0e76],.subsection-title[data-v-39de0e76]{font-size:13px;color:#bbb;margin-bottom:10px}.upload-zone[data-v-39de0e76]{border:1px dashed #3a3a3a;border-radius:10px;padding:18px;background:#252525;margin-bottom:18px}.hint[data-v-39de0e76],.loading-msg[data-v-39de0e76],.files[data-v-39de0e76],.muted[data-v-39de0e76]{color:#888;font-size:12px;line-height:1.5}.link[data-v-39de0e76]{color:#6ea8fe;text-decoration:none}.link[data-v-39de0e76]:hover{color:#9fc5ff}.btns[data-v-39de0e76],.run-row[data-v-39de0e76]{display:flex;gap:10px;flex-wrap:wrap}.opt-btn[data-v-39de0e76],.btn-run[data-v-39de0e76],.btn-delete[data-v-39de0e76],.download[data-v-39de0e76]{border:none;cursor:pointer;border-radius:7px}.opt-btn[data-v-39de0e76]{padding:8px 14px;color:#ccc;background:#2a2a2a;border:1px solid #3a3a3a}.btn-run[data-v-39de0e76]{padding:10px 18px;color:#fff;background:#3498db;font-weight:600}.btn-queue[data-v-39de0e76]{background:#27ae60}.btn-run[data-v-39de0e76]:disabled{opacity:.55;cursor:not-allowed}.selected-files[data-v-39de0e76]{margin-top:14px;color:#999;font-size:12px;word-break:break-all}.selected-files span[data-v-39de0e76]{display:block;margin:4px 0}.parse-card[data-v-39de0e76],.queue-payload[data-v-39de0e76]{margin-top:14px;padding:12px;border:1px solid #2a2a2a;border-radius:8px;background:#202020;color:#b8c1cc;font-size:12px}.queue-payload[data-v-39de0e76]{max-height:220px;overflow:auto;color:#8fd3ff;white-space:pre-wrap}.panel-header[data-v-39de0e76]{padding:16px 20px;border-bottom:1px solid #2a2a2a;font-size:15px;font-weight:600;color:#ddd}.task-list-wrap[data-v-39de0e76]{flex:1;padding:16px 20px;overflow:auto}.clean-result-summary[data-v-39de0e76]{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin-bottom:16px}.summary-card[data-v-39de0e76]{padding:14px 16px;border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e}.summary-card strong[data-v-39de0e76]{display:block;margin-top:8px;color:#eaf4ff;font-size:22px}.summary-label[data-v-39de0e76]{color:#8d8d8d;font-size:12px}.result-list-wrap[data-v-39de0e76]{border:1px solid #2a2a2a;border-radius:8px;background:#1e1e1e;min-height:180px;margin:0 0 16px}.result-list-header[data-v-39de0e76]{display:flex;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #2a2a2a;color:#ddd;font-size:14px}.empty-tasks[data-v-39de0e76]{color:#666;font-size:13px;padding:18px;text-align:center}.task-list[data-v-39de0e76]{list-style:none;margin:0;padding:12px}.task-item[data-v-39de0e76]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:12px 14px;border:1px solid #2a2a2a;border-radius:8px;margin-bottom:8px;background:#222}.left[data-v-39de0e76]{flex:1;min-width:0}.id[data-v-39de0e76]{color:#e0e0e0;font-size:13px;font-weight:600}.task-right[data-v-39de0e76]{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.status[data-v-39de0e76]{padding:4px 10px;border-radius:6px;font-size:12px}.status.success[data-v-39de0e76]{background:#2ecc712e;color:#2ecc71}.status.failed[data-v-39de0e76]{background:#e74c3c2e;color:#ff6b6b}.status.running[data-v-39de0e76]{background:#3498db2e;color:#3498db}.status.pending[data-v-39de0e76]{background:#95a5a62e;color:#bdc3c7}.result-hint[data-v-39de0e76]{margin-top:6px;color:#e0b96d}.file-progress[data-v-39de0e76]{margin-top:8px;max-width:520px}.file-progress-meta[data-v-39de0e76]{display:flex;justify-content:space-between;gap:12px;color:#d8c278;font-size:12px}.file-progress-track[data-v-39de0e76]{margin-top:5px;height:8px;border-radius:999px;overflow:hidden;background:#303030;border:1px solid #3b3b3b}.file-progress-bar[data-v-39de0e76]{height:100%;border-radius:inherit;background:linear-gradient(90deg,#4aa3ff,#f0c75e);transition:width .25s ease}.file-progress-count[data-v-39de0e76]{margin-top:4px;color:#858585;font-size:11px}.download[data-v-39de0e76]{padding:6px 10px;color:#d6ecff;background:#3498db2e}.btn-delete[data-v-39de0e76]{padding:6px 10px;color:#ff8f8f;background:#e74c3c1f}@media(max-width:1100px){.main-content[data-v-39de0e76]{flex-direction:column;height:auto}.left-panel[data-v-39de0e76]{width:100%;border-right:none;border-bottom:1px solid #2a2a2a}.clean-result-summary[data-v-39de0e76]{grid-template-columns:repeat(2,minmax(0,1fr))}} diff --git a/app/assets/similar-asin.js b/app/assets/similar-asin.js index 4c5c1eb..c5b02c2 100644 --- a/app/assets/similar-asin.js +++ b/app/assets/similar-asin.js @@ -1 +1 @@ -import{d as Le,o as Be,M as He,a as o,c as i,b as Je,B as qe,e as a,F as Z,r as ee,t as l,f as h,O as ge,n as je,g as p,h as H,i as J,E as d,a5 as Oe,a6 as Ke,V as pe,a7 as Ve,a8 as Ye,a9 as Qe,s as We,aa as Xe,ab as Ze,a3 as es,ac as ss,_ as ts,q as as,u as rs}from"./java-modules-DzYrjxib.js";import{e as ns}from"./brand-jr47vQUd.js";import{c as ls}from"./categorized-timers-JPA-olTr.js";const os={class:"page-shell module-page"},is={class:"main-content"},us={class:"left-panel"},cs={class:"upload-zone"},ds={class:"selected-files"},fs={key:0},vs={class:"run-row"},gs=["disabled"],ps=["disabled"],hs={key:0,class:"parse-card"},_s={key:1,class:"queue-payload"},ks={class:"right-panel"},ys={class:"task-list-wrap"},Is={class:"clean-result-summary"},Ss={class:"summary-card"},ws={class:"summary-card"},Ps={class:"summary-card"},Cs={class:"summary-card"},bs={class:"result-list-wrap"},Ns={key:0,class:"empty-tasks"},ms={key:1,class:"task-list clean-result-list"},Ts={class:"left"},Fs={class:"id"},Rs={class:"files"},Es={class:"files"},As={class:"files"},Us={class:"files"},Ds={key:0,class:"files result-hint"},$s={key:1,class:"file-progress"},xs={class:"file-progress-meta"},Ms={class:"file-progress-track"},zs={key:0,class:"file-progress-count"},Gs={class:"task-right"},Ls={class:"status running"},Bs=["onClick"],Hs={class:"result-list-wrap"},Js={key:0,class:"empty-tasks"},qs={key:1,class:"task-list clean-result-list"},js={class:"left"},Os={class:"id"},Ks={class:"files"},Vs={class:"files"},Ys={class:"files"},Qs={key:0,class:"files"},Ws={key:1,class:"files result-hint"},Xs={key:2,class:"file-progress"},Zs={class:"file-progress-meta"},et={class:"file-progress-track"},st={key:0,class:"file-progress-count"},tt={key:3,class:"files"},at={class:"task-right"},rt=["onClick"],nt=["onClick"],lt=3e3,ot=Le({__name:"BrandSimilarAsinTab",setup(ut){const A=p([]),C=p([]),k=p(null),b=p(null),U=p(!1),D=p(!1),I=p(""),f=p([]),u=p([]),_=p(null),q=p(!1);let N=null,se=0,m=!1;const T=ls("similar-asin"),F=p({pendingTaskCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),v=p([]),R=H(()=>k.value||b.value),j=H(()=>{const e=k.value;return!e?.taskId||v.value.some(t=>t.taskId===e.taskId)?null:{taskId:e.taskId,sourceFilename:e.sourceFilename,rowCount:e.acceptedRows,taskStatus:"PENDING",success:!1}}),te=H(()=>{const e=new Set([...f.value,...u.value]),s=v.value.filter(r=>{const n=y(r);return r.taskId!=null&&(e.has(r.taskId)||n==="RUNNING"||n==="PENDING")});return j.value?s.some(r=>r.taskId===j.value?.taskId)?s:[j.value,...s]:s}),ae=H(()=>v.value.filter(e=>{const s=y(e);return s!=="RUNNING"&&s!=="PENDING"}));function $(){return es("similar-asin").trim()}function x(e){if(!e)return"-";const s=new Date(e);if(Number.isNaN(s.getTime()))return e;const t=s.getFullYear(),r=String(s.getMonth()+1).padStart(2,"0"),n=String(s.getDate()).padStart(2,"0"),c=String(s.getHours()).padStart(2,"0"),g=String(s.getMinutes()).padStart(2,"0"),B=String(s.getSeconds()).padStart(2,"0");return`${t}-${r}-${n} ${c}:${g}:${B}`}function he(e){return e?e.length<=10?"***":`${e.slice(0,6)}***${e.slice(-4)}`:""}function _e(e){return{...e,data:e.data?{...e.data,api_key:he(String(e.data.api_key||""))}:e.data}}function re(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function ke(){return Number(re())||0}function O(){return`similar-asin:tasks:${re()}`}function ye(e){return{taskId:e.taskId,totalRows:e.totalRows,acceptedRows:e.acceptedRows,groupCount:e.groupCount,droppedRows:e.droppedRows}}function S(){if(typeof window>"u")return;const e=Array.from(new Set([...f.value,...u.value]));e.length?window.localStorage.setItem(O(),JSON.stringify(e)):window.localStorage.removeItem(O())}function Ie(){if(!(typeof window>"u"))try{const e=window.localStorage.getItem(O()),s=e?JSON.parse(e):[];f.value=Array.isArray(s)?s.filter(t=>typeof t=="number"&&t>0):[]}catch{f.value=[]}}async function ne(e){const s=J();if(!s?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传能力");const t=[];for(const r of e){const n=typeof r=="string"?r:r.absolutePath,c=typeof r=="string"?void 0:r.relativePath,g=await s.upload_file_to_java(n,c);if(!g?.success||!g.data)throw new Error(g?.error||g?.message||`上传失败:${n}`);t.push(g.data)}return t}async function Se(){const e=J();if(!e?.select_brand_xlsx_files||!e.upload_file_to_java){d.warning("当前桌面端未提供文件选择或上传能力");return}const s=await e.select_brand_xlsx_files();if(!s?.length)return;const t=await ne(s);C.value=t,A.value=t.map(r=>r.relativePath||r.originalFilename||r.fileKey),k.value=null,b.value=null,I.value=""}async function we(){const e=J();if(!e?.select_brand_folder||!e.upload_file_to_java){d.warning("当前桌面端未提供文件夹选择或上传能力");return}try{const s=await e.select_brand_folder();if(!s)return;const t=await ns(s);if(!t.success||!t.items?.length){d.warning(t.error||"该文件夹下没有可用的 xlsx 文件");return}const r=await ne(t.items);C.value=r,A.value=t.items.map(n=>n.relativePath||n.absolutePath),k.value=null,b.value=null,I.value="",d.success(`已选择文件夹内 ${t.items.length} 个 Excel 文件`)}catch(s){d.error(s instanceof Error?s.message:"选择失败")}}async function Pe(){if(!C.value.length){d.warning("请先选择 Excel");return}if(!$()){d.warning("请先在左上角设置中填写货源查询密钥");return}U.value=!0;try{const e=C.value.map(t=>({fileKey:t.fileKey,originalFilename:t.originalFilename,relativePath:t.relativePath})),s=await Oe(e,$());k.value=s,b.value=null,I.value="",d.success(`解析完成,共 ${s.acceptedRows} 条`)}catch(e){d.error(e instanceof Error?e.message:"解析失败")}finally{U.value=!1}}async function Ce(){const e=J(),s=k.value,t=s?.taskId;if(!t){d.warning("请先解析文件");return}if(!e?.enqueue_json){d.error("当前环境未启用 pywebview enqueue_json");return}if(!$()){d.warning("请先在左上角设置中填写货源查询密钥");return}D.value=!0;try{const r={type:"similar-asin-run",ts:Date.now(),data:{taskId:t,user_id:ke(),api_key:$(),sourceFileCount:s.sourceFileCount||0,totalRows:s.totalRows||0,acceptedRows:s.acceptedRows||0,groupCount:s.groupCount||0}};I.value=JSON.stringify(_e(r),null,2),await Ke(t);const n=await e.enqueue_json(r);if(!n?.success){d.error(n?.error||"推送失败");return}b.value=ye(s),Ne(t),be(),await M(),await z({force:!0}),d.success("已推送到 Python 队列")}finally{D.value=!1}}function be(){k.value=null,I.value=""}function Ne(e){f.value.includes(e)||(f.value=[...f.value,e],S()),w()}function K(e){f.value=f.value.filter(s=>s!==e),S()}function me(e){u.value.includes(e)||(u.value=[...u.value,e],S()),w()}function V(e){u.value=u.value.filter(s=>s!==e),S()}function w(){m||_.value==null&&Te(!0)}function le(){_.value!=null&&(T.clearTimer("task-poll",_.value),_.value=null)}function Te(e=!1){if(m)return;if(_.value!=null){if(!e)return;T.clearTimer("task-poll",_.value),_.value=null}const s=async()=>{_.value=null,!m&&(!f.value.length&&!u.value.length||(await Fe(),!m&&_.value==null&&(f.value.length||u.value.length)&&(_.value=T.setTimeout("task-poll",s,pe()))))};e?s():_.value=T.setTimeout("task-poll",s,pe())}async function Fe(){if(q.value||!f.value.length&&!u.value.length){!f.value.length&&!u.value.length&&le();return}q.value=!0;try{let e=!1,s=!1;const t=Array.from(new Set([...f.value,...u.value]));if(t.length){const r=await ss(t,{force:u.value.length>0});for(const n of r.items||[]){const c=n.task;if(!c?.id)continue;const g=n.items?.[0];if(g&&Re(g),(c.status==="SUCCESS"||c.status==="FAILED")&&(K(c.id),e=!0,c.status==="SUCCESS"?me(c.id):V(c.id)),g&&c.status==="SUCCESS"&&u.value.includes(c.id)){const B=(g.fileStatus||"").toUpperCase();(g.fileReady||B==="SUCCESS"||B==="FAILED")&&(V(c.id),e=!0,s=!0)}}r.missingTaskIds?.length&&(r.missingTaskIds.forEach(n=>{K(n),V(n)}),s=!0,e=!0)}e&&await M(),s&&await z(),Ee()}finally{q.value=!1}}function Re(e){if(!e.taskId&&!e.resultId)return;const s=v.value.findIndex(t=>e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId);s>=0?v.value[s]={...v.value[s],...e}:v.value=[e,...v.value]}function Ee(){if(!u.value.length)return;const e=[];for(const s of u.value){const t=v.value.find(c=>c.taskId===s);if(!t){e.push(s);continue}const r=(t.taskStatus||"").toUpperCase(),n=(t.fileStatus||"").toUpperCase();r==="FAILED"||t.fileReady||n==="SUCCESS"||n==="FAILED"||r==="SUCCESS"&&e.push(s)}u.value=e,S(),u.value.length&&w()}function Ae(){const e=v.value.filter(s=>s.taskId!=null&&P(s)).map(s=>s.taskId);u.value=Array.from(new Set(e)),S(),u.value.length&&w()}function Ue(){const e=v.value.filter(s=>s.taskId!=null&&y(s)==="RUNNING").map(s=>s.taskId);e.length&&(f.value=Array.from(new Set([...f.value,...e])),S(),w())}async function M(){F.value=await Ve()}async function z(e={}){const s=Date.now();if(!(!e.force&&v.value.length&&s-se{v.value=De(v.value,t.items||[]),se=Date.now()}).finally(()=>{N=null}),N)}function De(e,s){const t=new Map,r=new Map;for(const n of e||[])n.taskId!=null&&t.set(n.taskId,n),n.resultId!=null&&r.set(n.resultId,n);return(s||[]).map(n=>{const c=n.resultId!=null?r.get(n.resultId):n.taskId!=null?t.get(n.taskId):void 0;return $e(c,n)})}function $e(e,s){return!e||!((y(e)==="RUNNING"||P(e)||E(e))&&!E(s)&&!W(s))?s:{...s,fileJobId:s.fileJobId??e.fileJobId,fileStatus:s.fileStatus||e.fileStatus,fileError:s.fileError||e.fileError,fileReady:s.fileReady||e.fileReady,fileProgressPercent:Y(s.fileProgressPercent)?s.fileProgressPercent:e.fileProgressPercent,fileProgressCurrent:Y(s.fileProgressCurrent)?s.fileProgressCurrent:e.fileProgressCurrent,fileProgressTotal:Y(s.fileProgressTotal)?s.fileProgressTotal:e.fileProgressTotal,fileProgressMessage:(s.fileProgressMessage||"").trim()?s.fileProgressMessage:e.fileProgressMessage}}function Y(e){const s=Number(e);return Number.isFinite(s)&&s>0}function oe(e){const s=y(e);return s==="RUNNING"?"执行中":s==="PENDING"?"已解析待推送":P(e)?"结果生成中":Q(e)?"结果生成失败":s==="SUCCESS"||e.success?"已完成":s==="FAILED"?"失败":"等待中"}function xe(e){const s=y(e);return s==="RUNNING"||P(e)?"running":Q(e)||s==="FAILED"?"failed":s==="SUCCESS"||e.success?"success":"pending"}function P(e){const s=y(e),t=(e.fileStatus||"").toUpperCase();return!(s!=="SUCCESS"||W(e)||t==="FAILED"||t==="SUCCESS")}function y(e){return(e.taskStatus||"").toUpperCase()}function Q(e){return(e.fileStatus||"").toUpperCase()==="FAILED"}function G(e){if(Q(e))return e.fileError||"结果文件生成失败,请稍后重试或检查后端日志";if(E(e)||!P(e))return"";const s=(e.fileStatus||"").toUpperCase();return s==="RUNNING"?"任务已完成,正在等待 Coze 回流并组装结果文件,下载按钮稍后出现":s==="PENDING"?"任务已完成,结果文件已入队,正在等待后端开始处理":"任务已完成,正在生成结果文件,下载按钮稍后出现"}function W(e){return!!(e.resultId&&(e.fileReady||e.downloadUrl))}function L(e){const s=Number(e.fileProgressPercent||0);return Number.isFinite(s)&&s>0?Math.max(0,Math.min(100,Math.round(s))):fe(e)?de(e)==="PENDING"?6:10:0}function ie(e,s){const t=(e.fileProgressMessage||"").trim();return t?/coze/i.test(t)||/Coze|回流/.test(t)?/submitting/i.test(t)||/提交/.test(t)?"正在提交 Coze 批次":/生成结果|结果文件|组装/i.test(t)?"Coze 已回流,正在生成结果文件":/waiting/i.test(t)||/等待/.test(t)||/\d+\s*\/\s*\d+/.test(t)?"Coze 回流中,等待结果回传":"Coze 处理中":/assembling|xlsx|组装|生成结果/i.test(t)?"正在组装结果文件":t:s}function ue(e){const s=(e.fileProgressMessage||"").trim(),t=Me(s),r=t?.current??e.fileProgressCurrent??0,n=t?.total??e.fileProgressTotal??0;return/coze/i.test(s)||/Coze|回流/.test(s)?/submitting/i.test(s)||/提交/.test(s)?`Coze 提交批次 ${r}/${n}`:`Coze 回流批次 ${r}/${n}`:`当前阶段 ${r}/${n}`}function Me(e){const s=e.match(/(\d+)\s*\/\s*(\d+)/);if(!s)return null;const t=Number(s[1]),r=Number(s[2]);return!Number.isFinite(t)||!Number.isFinite(r)?null:{current:t,total:r}}function E(e){return(y(e)==="RUNNING"||P(e))&&(ce(e)||fe(e))}function ce(e){return X(e)||Number(e.fileProgressPercent||0)>0||!!(e.fileProgressMessage||"").trim()}function X(e){return(e.fileProgressTotal||0)>0}function de(e){return(e.fileStatus||"").toUpperCase()}function ze(e){const s=de(e);return e.fileJobId!=null||s==="PENDING"||s==="RUNNING"}function fe(e){return ze(e)&&!ce(e)}async function Ge(e){if(!e.resultId)return;const s=e.downloadUrl||Qe(e.resultId),t=e.resultFilename||`${e.sourceFilename||"similar-asin"}.xlsx`,r=await We(s,t,`similar-asin:${e.resultId}`);r.success?d.success(`已保存: ${r.path||t}`):r.error&&r.error!=="用户取消"&&d.error(r.error)}async function ve(e){try{e.taskStatus==="RUNNING"&&e.taskId?(await Xe(e.taskId),K(e.taskId)):e.resultId&&await Ze(e.resultId),await M(),await z({force:!0}),d.success("已删除")}catch(s){d.error(s instanceof Error?s.message:"删除失败")}}return Be(async()=>{Ie(),await Promise.all([M().catch(()=>{}),z().catch(()=>{})]),Ae(),Ue(),(f.value.length||u.value.length)&&w()}),He(()=>{m=!0,le(),T.clearScope()}),(e,s)=>(o(),i("div",os,[Je(qe,{active:"similar-asin"}),a("div",is,[a("aside",us,[s[1]||(s[1]=a("div",{class:"section-title"},"上传文件",-1)),a("div",cs,[s[0]||(s[0]=a("div",{class:"hint"},"选择 Excel 后点击解析,后端会提取 id、ASIN、国家、价格,每一行都会独立送检。",-1)),a("div",{class:"btns"},[a("button",{type:"button",class:"opt-btn",onClick:Se},"选择 Excel"),a("button",{type:"button",class:"opt-btn",onClick:we},"选择文件夹")]),a("div",ds,[A.value.length?(o(!0),i(Z,{key:1},ee(A.value,t=>(o(),i("span",{key:t},l(t),1))),128)):(o(),i("span",fs,"暂未选择文件"))])]),a("div",vs,[a("button",{type:"button",class:"btn-run",disabled:U.value||!C.value.length,onClick:Pe},l(U.value?"解析中...":"解析并创建任务"),9,gs),a("button",{type:"button",class:"btn-run btn-queue",disabled:D.value||!k.value?.taskId,onClick:Ce},l(D.value?"推送中...":"推送到 Python 队列"),9,ps)]),s[2]||(s[2]=a("p",{class:"loading-msg"},"Python 回传字段按 id、asin、国家、价格、标题、图片链接数组提交;后端接收分片后按 10 条一批送检,结果区展示真实 Coze 批次进度。",-1)),R.value?(o(),i("div",hs,[a("div",null,"任务 ID:"+l(R.value.taskId),1),a("div",null,"总行数:"+l(R.value.totalRows)+",有效:"+l(R.value.acceptedRows)+",过滤:"+l(R.value.droppedRows),1)])):h("",!0),I.value?(o(),i("pre",_s,l(I.value),1)):h("",!0)]),a("section",ks,[s[10]||(s[10]=a("div",{class:"panel-header"},"货源查询",-1)),a("div",ys,[a("div",Is,[a("div",Ss,[s[3]||(s[3]=a("span",{class:"summary-label"},"运行中任务",-1)),a("strong",null,l(F.value.pendingTaskCount),1)]),a("div",ws,[s[4]||(s[4]=a("span",{class:"summary-label"},"已结束任务",-1)),a("strong",null,l(F.value.processedTaskCount),1)]),a("div",Ps,[s[5]||(s[5]=a("span",{class:"summary-label"},"成功任务",-1)),a("strong",null,l(F.value.successTaskCount),1)]),a("div",Cs,[s[6]||(s[6]=a("span",{class:"summary-label"},"失败任务",-1)),a("strong",null,l(F.value.failedTaskCount),1)])]),s[9]||(s[9]=a("div",{class:"subsection-title"},"匹配任务",-1)),a("div",bs,[s[7]||(s[7]=a("div",{class:"result-list-header"},[a("span",null,"当前任务")],-1)),te.value.length?(o(),i("ul",ms,[(o(!0),i(Z,null,ee(te.value,t=>(o(),i("li",{key:`cur-${t.taskId}`,class:"task-item"},[a("div",Ts,[a("span",Fs,l(t.sourceFilename||"货源查询"),1),a("div",Rs,"任务 ID:"+l(t.taskId),1),a("div",Es,"开始时间:"+l(x(t.startedAt||t.createdAt)),1),a("div",As,"结束时间:"+l(x(t.finishedAt)),1),a("div",Us,"行数:"+l(t.rowCount??"-"),1),G(t)?(o(),i("div",Ds,l(G(t)),1)):h("",!0),E(t)?(o(),i("div",$s,[a("div",xs,[a("span",null,l(ie(t,"处理中")),1),a("span",null,"总进度 "+l(L(t))+"%",1)]),a("div",Ms,[a("div",{class:"file-progress-bar",style:ge({width:`${L(t)}%`})},null,4)]),X(t)?(o(),i("div",zs,l(ue(t)),1)):h("",!0)])):h("",!0)]),a("div",Gs,[a("span",Ls,l(oe(t)),1),a("button",{type:"button",class:"btn-delete",onClick:r=>ve(t)},"删除",8,Bs)])]))),128))])):(o(),i("div",Ns,"暂无当前任务"))]),a("div",Hs,[s[8]||(s[8]=a("div",{class:"result-list-header"},[a("span",null,"历史记录")],-1)),ae.value.length?(o(),i("ul",qs,[(o(!0),i(Z,null,ee(ae.value,t=>(o(),i("li",{key:`his-${t.resultId}-${t.taskId}`,class:"task-item"},[a("div",js,[a("span",Os,l(t.sourceFilename||"货源查询"),1),a("div",Ks,"任务 ID:"+l(t.taskId??"-"),1),a("div",Vs,"开始时间:"+l(x(t.startedAt||t.createdAt)),1),a("div",Ys,"结束时间:"+l(x(t.finishedAt)),1),t.resultFilename?(o(),i("div",Qs,l(t.resultFilename||"下载结果"),1)):h("",!0),G(t)?(o(),i("div",Ws,l(G(t)),1)):h("",!0),E(t)?(o(),i("div",Xs,[a("div",Zs,[a("span",null,l(ie(t,"结果生成中")),1),a("span",null,"总进度 "+l(L(t))+"%",1)]),a("div",et,[a("div",{class:"file-progress-bar",style:ge({width:`${L(t)}%`})},null,4)]),X(t)?(o(),i("div",st,l(ue(t)),1)):h("",!0)])):h("",!0),t.error?(o(),i("div",tt,"错误:"+l(t.error),1)):h("",!0)]),a("div",at,[a("span",{class:je(["status",xe(t)])},l(oe(t)),3),W(t)?(o(),i("button",{key:0,type:"button",class:"download",onClick:r=>Ge(t)},"下载",8,rt)):h("",!0),t.resultId?(o(),i("button",{key:1,type:"button",class:"btn-delete",onClick:r=>ve(t)},"删除",8,nt)):h("",!0)])]))),128))])):(o(),i("div",Js,"暂无历史记录"))])])])])]))}}),it=ts(ot,[["__scopeId","data-v-39de0e76"]]);as(it).use(rs).mount("#app"); +import{d as Be,o as He,M as Je,a as o,c as i,b as qe,B as je,e as a,F as ee,r as se,t as r,w as Oe,v as Ve,f as h,O as pe,n as Ke,g,h as H,i as J,E as d,a5 as Ye,a6 as Qe,V as he,a7 as We,a8 as Xe,a9 as Ze,s as es,aa as ss,ab as ts,a3 as as,ac as ls,_ as ns,q as rs,u as os}from"./java-modules-B8c-YG5x.js";import{e as is}from"./brand-COze15GJ.js";import{c as us}from"./categorized-timers-JPA-olTr.js";const cs={class:"page-shell module-page"},ds={class:"main-content"},fs={class:"left-panel"},vs={class:"upload-zone"},gs={class:"selected-files"},ps={key:0},hs={class:"condition-card"},ks={class:"switch-row"},_s={class:"run-row"},ys=["disabled"],Is=["disabled"],ws={key:0,class:"parse-card"},Ss={key:1,class:"queue-payload"},Ps={class:"right-panel"},Cs={class:"task-list-wrap"},bs={class:"clean-result-summary"},ms={class:"summary-card"},Ns={class:"summary-card"},Ts={class:"summary-card"},Fs={class:"summary-card"},Rs={class:"result-list-wrap"},Es={key:0,class:"empty-tasks"},As={key:1,class:"task-list clean-result-list"},Us={class:"left"},Ds={class:"id"},xs={class:"files"},$s={class:"files"},Ms={class:"files"},zs={class:"files"},Gs={key:0,class:"files result-hint"},Ls={key:1,class:"file-progress"},Bs={class:"file-progress-meta"},Hs={class:"file-progress-track"},Js={key:0,class:"file-progress-count"},qs={class:"task-right"},js={class:"status running"},Os=["onClick"],Vs={class:"result-list-wrap"},Ks={key:0,class:"empty-tasks"},Ys={key:1,class:"task-list clean-result-list"},Qs={class:"left"},Ws={class:"id"},Xs={class:"files"},Zs={class:"files"},et={class:"files"},st={key:0,class:"files"},tt={key:1,class:"files result-hint"},at={key:2,class:"file-progress"},lt={class:"file-progress-meta"},nt={class:"file-progress-track"},rt={key:0,class:"file-progress-count"},ot={key:3,class:"files"},it={class:"task-right"},ut=["onClick"],ct=["onClick"],dt=3e3,ft=Be({__name:"BrandSimilarAsinTab",setup(gt){const A=g([]),C=g([]),_=g(null),b=g(null),U=g(!1),D=g(!1),q=g(!1),I=g(""),f=g([]),u=g([]),k=g(null),j=g(!1);let m=null,te=0,N=!1;const T=us("similar-asin"),F=g({pendingTaskCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),v=g([]),R=H(()=>_.value||b.value),O=H(()=>{const e=_.value;return!e?.taskId||v.value.some(t=>t.taskId===e.taskId)?null:{taskId:e.taskId,sourceFilename:e.sourceFilename,rowCount:e.acceptedRows,taskStatus:"PENDING",success:!1}}),ae=H(()=>{const e=new Set([...f.value,...u.value]),s=v.value.filter(l=>{const n=y(l);return l.taskId!=null&&(e.has(l.taskId)||n==="RUNNING"||n==="PENDING")});return O.value?s.some(l=>l.taskId===O.value?.taskId)?s:[O.value,...s]:s}),le=H(()=>v.value.filter(e=>{const s=y(e);return s!=="RUNNING"&&s!=="PENDING"}));function x(){return as("similar-asin").trim()}function $(e){if(!e)return"-";const s=new Date(e);if(Number.isNaN(s.getTime()))return e;const t=s.getFullYear(),l=String(s.getMonth()+1).padStart(2,"0"),n=String(s.getDate()).padStart(2,"0"),c=String(s.getHours()).padStart(2,"0"),p=String(s.getMinutes()).padStart(2,"0"),B=String(s.getSeconds()).padStart(2,"0");return`${t}-${l}-${n} ${c}:${p}:${B}`}function ke(e){return e?e.length<=10?"***":`${e.slice(0,6)}***${e.slice(-4)}`:""}function _e(e){return{...e,data:e.data?{...e.data,api_key:ke(String(e.data.api_key||""))}:e.data}}function ne(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function ye(){return Number(ne())||0}function V(){return`similar-asin:tasks:${ne()}`}function Ie(e){return{taskId:e.taskId,totalRows:e.totalRows,acceptedRows:e.acceptedRows,groupCount:e.groupCount,droppedRows:e.droppedRows}}function w(){if(typeof window>"u")return;const e=Array.from(new Set([...f.value,...u.value]));e.length?window.localStorage.setItem(V(),JSON.stringify(e)):window.localStorage.removeItem(V())}function we(){if(!(typeof window>"u"))try{const e=window.localStorage.getItem(V()),s=e?JSON.parse(e):[];f.value=Array.isArray(s)?s.filter(t=>typeof t=="number"&&t>0):[]}catch{f.value=[]}}async function re(e){const s=J();if(!s?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传能力");const t=[];for(const l of e){const n=typeof l=="string"?l:l.absolutePath,c=typeof l=="string"?void 0:l.relativePath,p=await s.upload_file_to_java(n,c);if(!p?.success||!p.data)throw new Error(p?.error||p?.message||`上传失败:${n}`);t.push(p.data)}return t}async function Se(){const e=J();if(!e?.select_brand_xlsx_files||!e.upload_file_to_java){d.warning("当前桌面端未提供文件选择或上传能力");return}const s=await e.select_brand_xlsx_files();if(!s?.length)return;const t=await re(s);C.value=t,A.value=t.map(l=>l.relativePath||l.originalFilename||l.fileKey),_.value=null,b.value=null,I.value=""}async function Pe(){const e=J();if(!e?.select_brand_folder||!e.upload_file_to_java){d.warning("当前桌面端未提供文件夹选择或上传能力");return}try{const s=await e.select_brand_folder();if(!s)return;const t=await is(s);if(!t.success||!t.items?.length){d.warning(t.error||"该文件夹下没有可用的 xlsx 文件");return}const l=await re(t.items);C.value=l,A.value=t.items.map(n=>n.relativePath||n.absolutePath),_.value=null,b.value=null,I.value="",d.success(`已选择文件夹内 ${t.items.length} 个 Excel 文件`)}catch(s){d.error(s instanceof Error?s.message:"选择失败")}}async function Ce(){if(!C.value.length){d.warning("请先选择 Excel");return}if(!x()){d.warning("请先在左上角设置中填写货源查询密钥");return}U.value=!0;try{const e=C.value.map(t=>({fileKey:t.fileKey,originalFilename:t.originalFilename,relativePath:t.relativePath})),s=await Ye(e,x(),q.value);_.value=s,b.value=null,I.value="",d.success(`解析完成,共 ${s.acceptedRows} 条`)}catch(e){d.error(e instanceof Error?e.message:"解析失败")}finally{U.value=!1}}async function be(){const e=J(),s=_.value,t=s?.taskId;if(!t){d.warning("请先解析文件");return}if(!e?.enqueue_json){d.error("当前环境未启用 pywebview enqueue_json");return}if(!x()){d.warning("请先在左上角设置中填写货源查询密钥");return}D.value=!0;try{const l={type:"similar-asin-run",ts:Date.now(),data:{taskId:t,user_id:ye(),api_key:x(),sourceFileCount:s.sourceFileCount||0,totalRows:s.totalRows||0,acceptedRows:s.acceptedRows||0,groupCount:s.groupCount||0}};I.value=JSON.stringify(_e(l),null,2),await Qe(t);const n=await e.enqueue_json(l);if(!n?.success){d.error(n?.error||"推送失败");return}b.value=Ie(s),Ne(t),me(),await M(),await z({force:!0}),d.success("已推送到 Python 队列")}finally{D.value=!1}}function me(){_.value=null,I.value=""}function Ne(e){f.value.includes(e)||(f.value=[...f.value,e],w()),S()}function K(e){f.value=f.value.filter(s=>s!==e),w()}function Te(e){u.value.includes(e)||(u.value=[...u.value,e],w()),S()}function Y(e){u.value=u.value.filter(s=>s!==e),w()}function S(){N||k.value==null&&Fe(!0)}function oe(){k.value!=null&&(T.clearTimer("task-poll",k.value),k.value=null)}function Fe(e=!1){if(N)return;if(k.value!=null){if(!e)return;T.clearTimer("task-poll",k.value),k.value=null}const s=async()=>{k.value=null,!N&&(!f.value.length&&!u.value.length||(await Re(),!N&&k.value==null&&(f.value.length||u.value.length)&&(k.value=T.setTimeout("task-poll",s,he()))))};e?s():k.value=T.setTimeout("task-poll",s,he())}async function Re(){if(j.value||!f.value.length&&!u.value.length){!f.value.length&&!u.value.length&&oe();return}j.value=!0;try{let e=!1,s=!1;const t=Array.from(new Set([...f.value,...u.value]));if(t.length){const l=await ls(t,{force:u.value.length>0});for(const n of l.items||[]){const c=n.task;if(!c?.id)continue;const p=n.items?.[0];if(p&&Ee(p),(c.status==="SUCCESS"||c.status==="FAILED")&&(K(c.id),e=!0,c.status==="SUCCESS"?Te(c.id):Y(c.id)),p&&c.status==="SUCCESS"&&u.value.includes(c.id)){const B=(p.fileStatus||"").toUpperCase();(p.fileReady||B==="SUCCESS"||B==="FAILED")&&(Y(c.id),e=!0,s=!0)}}l.missingTaskIds?.length&&(l.missingTaskIds.forEach(n=>{K(n),Y(n)}),s=!0,e=!0)}e&&await M(),s&&await z(),Ae()}finally{j.value=!1}}function Ee(e){if(!e.taskId&&!e.resultId)return;const s=v.value.findIndex(t=>e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId);s>=0?v.value[s]={...v.value[s],...e}:v.value=[e,...v.value]}function Ae(){if(!u.value.length)return;const e=[];for(const s of u.value){const t=v.value.find(c=>c.taskId===s);if(!t){e.push(s);continue}const l=(t.taskStatus||"").toUpperCase(),n=(t.fileStatus||"").toUpperCase();l==="FAILED"||t.fileReady||n==="SUCCESS"||n==="FAILED"||l==="SUCCESS"&&e.push(s)}u.value=e,w(),u.value.length&&S()}function Ue(){const e=v.value.filter(s=>s.taskId!=null&&P(s)).map(s=>s.taskId);u.value=Array.from(new Set(e)),w(),u.value.length&&S()}function De(){const e=v.value.filter(s=>s.taskId!=null&&y(s)==="RUNNING").map(s=>s.taskId);e.length&&(f.value=Array.from(new Set([...f.value,...e])),w(),S())}async function M(){F.value=await We()}async function z(e={}){const s=Date.now();if(!(!e.force&&v.value.length&&s-te{v.value=xe(v.value,t.items||[]),te=Date.now()}).finally(()=>{m=null}),m)}function xe(e,s){const t=new Map,l=new Map;for(const n of e||[])n.taskId!=null&&t.set(n.taskId,n),n.resultId!=null&&l.set(n.resultId,n);return(s||[]).map(n=>{const c=n.resultId!=null?l.get(n.resultId):n.taskId!=null?t.get(n.taskId):void 0;return $e(c,n)})}function $e(e,s){return!e||!((y(e)==="RUNNING"||P(e)||E(e))&&!E(s)&&!X(s))?s:{...s,fileJobId:s.fileJobId??e.fileJobId,fileStatus:s.fileStatus||e.fileStatus,fileError:s.fileError||e.fileError,fileReady:s.fileReady||e.fileReady,fileProgressPercent:Q(s.fileProgressPercent)?s.fileProgressPercent:e.fileProgressPercent,fileProgressCurrent:Q(s.fileProgressCurrent)?s.fileProgressCurrent:e.fileProgressCurrent,fileProgressTotal:Q(s.fileProgressTotal)?s.fileProgressTotal:e.fileProgressTotal,fileProgressMessage:(s.fileProgressMessage||"").trim()?s.fileProgressMessage:e.fileProgressMessage}}function Q(e){const s=Number(e);return Number.isFinite(s)&&s>0}function ie(e){const s=y(e);return s==="RUNNING"?"执行中":s==="PENDING"?"已解析待推送":P(e)?"结果生成中":W(e)?"结果生成失败":s==="SUCCESS"||e.success?"已完成":s==="FAILED"?"失败":"等待中"}function Me(e){const s=y(e);return s==="RUNNING"||P(e)?"running":W(e)||s==="FAILED"?"failed":s==="SUCCESS"||e.success?"success":"pending"}function P(e){const s=y(e),t=(e.fileStatus||"").toUpperCase();return!(s!=="SUCCESS"||X(e)||t==="FAILED"||t==="SUCCESS")}function y(e){return(e.taskStatus||"").toUpperCase()}function W(e){return(e.fileStatus||"").toUpperCase()==="FAILED"}function G(e){if(W(e))return e.fileError||"结果文件生成失败,请稍后重试或检查后端日志";if(E(e)||!P(e))return"";const s=(e.fileStatus||"").toUpperCase();return s==="RUNNING"?"任务已完成,正在等待 Coze 回流并组装结果文件,下载按钮稍后出现":s==="PENDING"?"任务已完成,结果文件已入队,正在等待后端开始处理":"任务已完成,正在生成结果文件,下载按钮稍后出现"}function X(e){return!!(e.resultId&&(e.fileReady||e.downloadUrl))}function L(e){const s=Number(e.fileProgressPercent||0);return Number.isFinite(s)&&s>0?Math.max(0,Math.min(100,Math.round(s))):ve(e)?fe(e)==="PENDING"?6:10:0}function ue(e,s){const t=(e.fileProgressMessage||"").trim();return t?/coze/i.test(t)||/Coze|回流/.test(t)?/submitting/i.test(t)||/提交/.test(t)?"正在提交 Coze 批次":/生成结果|结果文件|组装/i.test(t)?"Coze 已回流,正在生成结果文件":/waiting/i.test(t)||/等待/.test(t)||/\d+\s*\/\s*\d+/.test(t)?"Coze 回流中,等待结果回传":"Coze 处理中":/assembling|xlsx|组装|生成结果/i.test(t)?"正在组装结果文件":t:s}function ce(e){const s=(e.fileProgressMessage||"").trim(),t=ze(s),l=t?.current??e.fileProgressCurrent??0,n=t?.total??e.fileProgressTotal??0;return/coze/i.test(s)||/Coze|回流/.test(s)?/submitting/i.test(s)||/提交/.test(s)?`Coze 提交批次 ${l}/${n}`:`Coze 回流批次 ${l}/${n}`:`当前阶段 ${l}/${n}`}function ze(e){const s=e.match(/(\d+)\s*\/\s*(\d+)/);if(!s)return null;const t=Number(s[1]),l=Number(s[2]);return!Number.isFinite(t)||!Number.isFinite(l)?null:{current:t,total:l}}function E(e){return(y(e)==="RUNNING"||P(e))&&(de(e)||ve(e))}function de(e){return Z(e)||Number(e.fileProgressPercent||0)>0||!!(e.fileProgressMessage||"").trim()}function Z(e){return(e.fileProgressTotal||0)>0}function fe(e){return(e.fileStatus||"").toUpperCase()}function Ge(e){const s=fe(e);return e.fileJobId!=null||s==="PENDING"||s==="RUNNING"}function ve(e){return Ge(e)&&!de(e)}async function Le(e){if(!e.resultId)return;const s=e.downloadUrl||Ze(e.resultId),t=e.resultFilename||`${e.sourceFilename||"similar-asin"}.xlsx`,l=await es(s,t,`similar-asin:${e.resultId}`);l.success?d.success(`已保存: ${l.path||t}`):l.error&&l.error!=="用户取消"&&d.error(l.error)}async function ge(e){try{e.taskStatus==="RUNNING"&&e.taskId?(await ss(e.taskId),K(e.taskId)):e.resultId&&await ts(e.resultId),await M(),await z({force:!0}),d.success("已删除")}catch(s){d.error(s instanceof Error?s.message:"删除失败")}}return He(async()=>{we(),await Promise.all([M().catch(()=>{}),z().catch(()=>{})]),Ue(),De(),(f.value.length||u.value.length)&&S()}),Je(()=>{N=!0,oe(),T.clearScope()}),(e,s)=>(o(),i("div",cs,[qe(je,{active:"similar-asin"}),a("div",ds,[a("aside",fs,[s[5]||(s[5]=a("div",{class:"section-title"},"上传文件",-1)),a("div",vs,[s[1]||(s[1]=a("div",{class:"hint"},"选择 Excel 后点击解析,后端会提取 id、ASIN、国家、价格,每一行都会独立送检。",-1)),a("div",{class:"btns"},[a("button",{type:"button",class:"opt-btn",onClick:Se},"选择 Excel"),a("button",{type:"button",class:"opt-btn",onClick:Pe},"选择文件夹")]),a("div",gs,[A.value.length?(o(!0),i(ee,{key:1},se(A.value,t=>(o(),i("span",{key:t},r(t),1))),128)):(o(),i("span",ps,"暂未选择文件"))])]),a("div",hs,[s[4]||(s[4]=a("div",{class:"section-title"},"检测条件",-1)),a("label",ks,[s[2]||(s[2]=a("span",null,[a("strong",null,"图片检测"),a("em",null,"开启后请求 Coze 时携带 img_switch=true")],-1)),Oe(a("input",{"onUpdate:modelValue":s[0]||(s[0]=t=>q.value=t),type:"checkbox"},null,512),[[Ve,q.value]]),s[3]||(s[3]=a("i",null,null,-1))])]),a("div",_s,[a("button",{type:"button",class:"btn-run",disabled:U.value||!C.value.length,onClick:Ce},r(U.value?"解析中...":"解析并创建任务"),9,ys),a("button",{type:"button",class:"btn-run btn-queue",disabled:D.value||!_.value?.taskId,onClick:be},r(D.value?"推送中...":"推送到 Python 队列"),9,Is)]),s[6]||(s[6]=a("p",{class:"loading-msg"},"Python 回传字段按 id、asin、国家、价格、标题、图片链接数组提交;后端接收分片后按 10 条一批送检,结果区展示真实 Coze 批次进度。",-1)),R.value?(o(),i("div",ws,[a("div",null,"任务 ID:"+r(R.value.taskId),1),a("div",null,"总行数:"+r(R.value.totalRows)+",有效:"+r(R.value.acceptedRows)+",过滤:"+r(R.value.droppedRows),1)])):h("",!0),I.value?(o(),i("pre",Ss,r(I.value),1)):h("",!0)]),a("section",Ps,[s[14]||(s[14]=a("div",{class:"panel-header"},"货源查询",-1)),a("div",Cs,[a("div",bs,[a("div",ms,[s[7]||(s[7]=a("span",{class:"summary-label"},"运行中任务",-1)),a("strong",null,r(F.value.pendingTaskCount),1)]),a("div",Ns,[s[8]||(s[8]=a("span",{class:"summary-label"},"已结束任务",-1)),a("strong",null,r(F.value.processedTaskCount),1)]),a("div",Ts,[s[9]||(s[9]=a("span",{class:"summary-label"},"成功任务",-1)),a("strong",null,r(F.value.successTaskCount),1)]),a("div",Fs,[s[10]||(s[10]=a("span",{class:"summary-label"},"失败任务",-1)),a("strong",null,r(F.value.failedTaskCount),1)])]),s[13]||(s[13]=a("div",{class:"subsection-title"},"匹配任务",-1)),a("div",Rs,[s[11]||(s[11]=a("div",{class:"result-list-header"},[a("span",null,"当前任务")],-1)),ae.value.length?(o(),i("ul",As,[(o(!0),i(ee,null,se(ae.value,t=>(o(),i("li",{key:`cur-${t.taskId}`,class:"task-item"},[a("div",Us,[a("span",Ds,r(t.sourceFilename||"货源查询"),1),a("div",xs,"任务 ID:"+r(t.taskId),1),a("div",$s,"开始时间:"+r($(t.startedAt||t.createdAt)),1),a("div",Ms,"结束时间:"+r($(t.finishedAt)),1),a("div",zs,"行数:"+r(t.rowCount??"-"),1),G(t)?(o(),i("div",Gs,r(G(t)),1)):h("",!0),E(t)?(o(),i("div",Ls,[a("div",Bs,[a("span",null,r(ue(t,"处理中")),1),a("span",null,"总进度 "+r(L(t))+"%",1)]),a("div",Hs,[a("div",{class:"file-progress-bar",style:pe({width:`${L(t)}%`})},null,4)]),Z(t)?(o(),i("div",Js,r(ce(t)),1)):h("",!0)])):h("",!0)]),a("div",qs,[a("span",js,r(ie(t)),1),a("button",{type:"button",class:"btn-delete",onClick:l=>ge(t)},"删除",8,Os)])]))),128))])):(o(),i("div",Es,"暂无当前任务"))]),a("div",Vs,[s[12]||(s[12]=a("div",{class:"result-list-header"},[a("span",null,"历史记录")],-1)),le.value.length?(o(),i("ul",Ys,[(o(!0),i(ee,null,se(le.value,t=>(o(),i("li",{key:`his-${t.resultId}-${t.taskId}`,class:"task-item"},[a("div",Qs,[a("span",Ws,r(t.sourceFilename||"货源查询"),1),a("div",Xs,"任务 ID:"+r(t.taskId??"-"),1),a("div",Zs,"开始时间:"+r($(t.startedAt||t.createdAt)),1),a("div",et,"结束时间:"+r($(t.finishedAt)),1),t.resultFilename?(o(),i("div",st,r(t.resultFilename||"下载结果"),1)):h("",!0),G(t)?(o(),i("div",tt,r(G(t)),1)):h("",!0),E(t)?(o(),i("div",at,[a("div",lt,[a("span",null,r(ue(t,"结果生成中")),1),a("span",null,"总进度 "+r(L(t))+"%",1)]),a("div",nt,[a("div",{class:"file-progress-bar",style:pe({width:`${L(t)}%`})},null,4)]),Z(t)?(o(),i("div",rt,r(ce(t)),1)):h("",!0)])):h("",!0),t.error?(o(),i("div",ot,"错误:"+r(t.error),1)):h("",!0)]),a("div",it,[a("span",{class:Ke(["status",Me(t)])},r(ie(t)),3),X(t)?(o(),i("button",{key:0,type:"button",class:"download",onClick:l=>Le(t)},"下载",8,ut)):h("",!0),t.resultId?(o(),i("button",{key:1,type:"button",class:"btn-delete",onClick:l=>ge(t)},"删除",8,ct)):h("",!0)])]))),128))])):(o(),i("div",Ks,"暂无历史记录"))])])])])]))}}),vt=ns(ft,[["__scopeId","data-v-4ed8ec44"]]);rs(vt).use(os).mount("#app"); diff --git a/app/assets/split.js b/app/assets/split.js index c177fe1..b530fe6 100644 --- a/app/assets/split.js +++ b/app/assets/split.js @@ -1 +1 @@ -import{d as L,o as q,a,c as n,b as O,B as W,e,F as S,r as E,t as i,f as v,n as x,w as k,x as V,H as M,g as d,h as G,i as $,E as r,I as Q,J as X,p as Y,v as Z,K as ss,L as es,s as ts,_ as ls,q as as,u as ns}from"./java-modules-DzYrjxib.js";import{e as os}from"./brand-jr47vQUd.js";const is={class:"page-shell module-page"},rs={class:"main-content"},us={class:"left-panel"},ds={class:"upload-zone"},cs={class:"selected-files clean-placeholder split-selected-files"},ps={key:0,class:"more-line"},vs={key:1},fs={class:"option-group column-option-group"},_s={class:"column-toolbar"},ms={class:"column-count"},ys={class:"column-actions"},gs={key:0,class:"column-grid"},hs=["value"],bs={key:1,class:"empty-column-state"},ws={class:"option-group"},ks={class:"radio-item active"},Cs={class:"desc"},Ss={class:"option-group"},xs={class:"option-group"},Fs={key:0,class:"split-input-card"},Ps={key:1,class:"split-input-card"},Es={class:"run-row"},$s=["disabled"],Is={class:"loading-msg"},Rs={class:"right-panel"},Bs={class:"task-list-wrap"},Us={class:"clean-result-summary"},Vs={class:"summary-card"},Ms={class:"summary-card"},Ts={class:"summary-card"},Ds={class:"result-list-wrap"},Hs={key:0,class:"empty-tasks"},Ks={key:1,class:"task-list clean-result-list"},Ns={class:"left split-result-main"},js=["title"],As={key:0,class:"files"},zs={key:1,class:"time"},Js={key:2,class:"files"},Ls={key:3,class:"files split-entry-list"},qs={key:4,class:"files"},Os={class:"task-right split-result-actions"},Ws=["onClick"],Gs=["onClick"],Qs=L({__name:"BrandSplitTab",setup(Ys){const f=d([]),C=d(""),c=d([]),_=d([]),p=d([]),I=d(0),u=d("rows_per_file"),m=d(2e3),y=d(5),g=d(!1),h=d([]),b=d({total:0,successCount:0,failedCount:0,items:[]}),F=G(()=>f.value.slice(0,8));function T(l){b.value={total:l.length,successCount:l.filter(s=>s.success).length,failedCount:l.filter(s=>!s.success).length,items:l}}async function R(l){const s=$();if(!s?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const o of l){const U=typeof o=="string"?o:o.absolutePath,J=typeof o=="string"?void 0:o.relativePath,w=await s.upload_file_to_java(U,J);if(!w?.success||!w.data)throw new Error(w?.error||w?.message||`上传失败:${U}`);t.push(w.data)}return t}async function B(l){const s=await Y(l);_.value=s.headers||[],p.value=[...s.headers||[]],I.value=s.totalRows||0}async function D(l,s){f.value=l,C.value="",c.value=await R(l),c.value.length>0&&await B(c.value[0].fileKey),r.success(s)}async function H(){const l=$();if(!l?.select_brand_xlsx_files){r.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const s=await l.select_brand_xlsx_files();if(!s?.length)return;await D(s,`已选择 ${s.length} 个待拆分文件`)}catch(s){r.error(s instanceof Error?s.message:"选择失败")}}async function K(){const l=$();if(!l?.select_brand_folder){r.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const s=await l.select_brand_folder();if(!s)return;C.value=s.split(/[/\\]/).filter(Boolean).pop()||"";const t=await os(s);if(t.success&&t.items?.length){f.value=t.items.map(o=>o.relativePath),c.value=await R(t.items),c.value.length>0&&await B(c.value[0].fileKey),r.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`);return}r.warning(t.error||"该文件夹下没有 xlsx 文件")}catch(s){r.error(s instanceof Error?s.message:"选择失败")}}async function N(){if(!c.value.length){r.warning("请先选择待拆分 Excel 文件或文件夹");return}if(!p.value.length){r.warning("请至少选择一列保留列");return}if(u.value==="rows_per_file"&&(!m.value||m.value<=0)){r.warning("请输入有效的每份条数");return}if(u.value==="parts"&&(!y.value||y.value<=0)){r.warning("请输入有效的拆分份数");return}try{g.value=!0;const l=await Q({files:c.value.map(s=>({fileKey:s.fileKey,originalFilename:s.originalFilename,relativePath:s.relativePath})),selectedColumns:p.value,splitMode:u.value,rowsPerFile:u.value==="rows_per_file"&&m.value||void 0,parts:u.value==="parts"&&y.value||void 0,archiveName:c.value.some(s=>!!s.relativePath)&&C.value?C.value:void 0});b.value=l,h.value=l.items||[],await P(),r.success("数据拆分完成")}catch(l){r.error(l instanceof Error?l.message:"数据拆分失败")}finally{g.value=!1}}async function P(){try{const l=await X();h.value=l.items||[],T(h.value)}catch{}}async function j(l){try{await ss(l),await P(),r.success("已删除")}catch(s){r.error(s instanceof Error?s.message:"删除失败")}}function A(l){const s=l.slice(0,4).map(o=>o.rowCount!==void 0?`${o.filename}(${o.rowCount}条)`:o.filename);return l.length-s.length>0?`${s.join("、")} 等 ${l.length} 个文件`:s.join("、")}async function z(l){const s=l.downloadUrl||(l.resultId?es(l.resultId):"");if(!s){r.warning("当前结果没有下载地址");return}const t=l.outputFilename||`${new Date().toISOString().slice(0,10).replace(/-/g,"")}.zip`,o=await ts(s,t,l.resultId?`split:${l.resultId}`:void 0);o.success?r.success(`已保存:${o.path||t}`):o.error&&o.error!=="用户取消"&&r.error(o.error)}return q(()=>{P().catch(()=>{})}),(l,s)=>(a(),n("div",is,[O(W,{active:"split"}),e("div",rs,[e("aside",us,[s[14]||(s[14]=e("div",{class:"section-title"},"选择文件",-1)),e("div",ds,[s[7]||(s[7]=e("div",{class:"hint"},"选择需要拆分的 Excel 文件或文件夹,按规则拆成多个 Excel 文件。",-1)),e("div",{class:"btns"},[e("button",{type:"button",class:"opt-btn",onClick:H},"选择 Excel 文件"),e("button",{type:"button",class:"opt-btn",onClick:K},"选择文件夹")]),e("div",cs,[f.value.length?(a(),n(S,{key:0},[(a(!0),n(S,null,E(F.value,t=>(a(),n("span",{key:t},i(t),1))),128)),f.value.length>F.value.length?(a(),n("span",ps," 还有 "+i(f.value.length-F.value.length)+" 个文件未展开显示 ",1)):v("",!0)],64)):(a(),n("span",vs,"暂未选择待拆分文件"))])]),s[15]||(s[15]=e("div",{class:"section-title"},"保留列设置",-1)),e("div",fs,[e("div",_s,[e("span",ms,"已选择 "+i(p.value.length)+" / "+i(_.value.length)+" 列",1),e("div",ys,[e("button",{type:"button",class:"opt-btn small",onClick:s[0]||(s[0]=t=>p.value=[..._.value])},"全选"),e("button",{type:"button",class:"opt-btn small",onClick:s[1]||(s[1]=t=>p.value=[])},"清空")])]),_.value.length?(a(),n("div",gs,[(a(!0),n(S,null,E(_.value,t=>(a(),n("label",{key:t,class:x(["column-item",{active:p.value.includes(t)}])},[k(e("input",{"onUpdate:modelValue":s[2]||(s[2]=o=>p.value=o),type:"checkbox",value:t},null,8,hs),[[Z,p.value]]),e("span",null,i(t),1)],2))),128))])):(a(),n("div",bs,"请选择 Excel 文件后读取表头并填充可保留列"))]),s[16]||(s[16]=e("div",{class:"section-title"},"总条数",-1)),e("div",ws,[e("label",ks,[s[9]||(s[9]=e("input",{type:"checkbox",checked:"",disabled:""},null,-1)),e("div",null,[s[8]||(s[8]=e("span",{class:"label"},"当前数据总条数",-1)),e("div",Cs,i(I.value)+" 条(不含表头)",1)])])]),s[17]||(s[17]=e("div",{class:"section-title"},"拆分模式",-1)),e("div",Ss,[e("label",{class:x(["radio-item",{active:u.value==="rows_per_file"}])},[k(e("input",{"onUpdate:modelValue":s[3]||(s[3]=t=>u.value=t),type:"radio",value:"rows_per_file",name:"split-mode"},null,512),[[V,u.value]]),s[10]||(s[10]=e("div",null,[e("span",{class:"label"},"按每份条数"),e("div",{class:"desc"},"例如每份 2000 条,最后一份放剩余数据")],-1))],2),e("label",{class:x(["radio-item",{active:u.value==="parts"}])},[k(e("input",{"onUpdate:modelValue":s[4]||(s[4]=t=>u.value=t),type:"radio",value:"parts",name:"split-mode"},null,512),[[V,u.value]]),s[11]||(s[11]=e("div",null,[e("span",{class:"label"},"按份数平均拆分"),e("div",{class:"desc"},"例如拆 5 份,按总条数尽量平均分配")],-1))],2)]),s[18]||(s[18]=e("div",{class:"section-title"},"拆分参数",-1)),e("div",xs,[u.value==="rows_per_file"?(a(),n("label",Fs,[s[12]||(s[12]=e("span",{class:"label"},"每份条数",-1)),k(e("input",{"onUpdate:modelValue":s[5]||(s[5]=t=>m.value=t),class:"split-number-input",type:"number",min:"1",placeholder:"例如 2000"},null,512),[[M,m.value,void 0,{number:!0}]])])):(a(),n("label",Ps,[s[13]||(s[13]=e("span",{class:"label"},"拆分份数",-1)),k(e("input",{"onUpdate:modelValue":s[6]||(s[6]=t=>y.value=t),class:"split-number-input",type:"number",min:"1",placeholder:"例如 5"},null,512),[[M,y.value,void 0,{number:!0}]])]))]),e("div",Es,[e("button",{type:"button",class:"btn-run",disabled:g.value,onClick:N},i(g.value?"拆分中...":"开始拆分"),9,$s),e("span",Is,i(g.value?"正在拆分并上传结果,请稍候…":"选择文件、保留列和拆分规则后即可执行拆分,结果会显示在右侧供下载"),1)])]),e("section",Rs,[s[23]||(s[23]=e("div",{class:"panel-header"},"拆分结果",-1)),e("div",Bs,[e("div",Us,[e("div",Vs,[s[19]||(s[19]=e("span",{class:"summary-label"},"已处理文件",-1)),e("strong",null,i(b.value.total),1)]),e("div",Ms,[s[20]||(s[20]=e("span",{class:"summary-label"},"成功结果",-1)),e("strong",null,i(b.value.successCount),1)]),e("div",Ts,[s[21]||(s[21]=e("span",{class:"summary-label"},"失败文件",-1)),e("strong",null,i(b.value.failedCount),1)])]),e("div",Ds,[s[22]||(s[22]=e("div",{class:"result-list-header"},[e("span",null,"拆分结果压缩包列表")],-1)),h.value.length===0?(a(),n("div",Hs," 暂无拆分结果,完成数据拆分后会在这里展示压缩包文件 ")):(a(),n("ul",Ks,[(a(!0),n(S,null,E(h.value,t=>(a(),n("li",{key:`${t.resultId||t.outputFilename||t.sourceFilename}-${t.rowCount||0}`,class:"task-item split-result-item"},[e("div",Ns,[e("span",{class:"id",title:t.sourceFilename},i(t.sourceFilename||"-"),9,js),t.outputFilename?(a(),n("div",As,"压缩包文件:"+i(t.outputFilename),1)):v("",!0),t.rowCount!==void 0?(a(),n("div",zs,"压缩包共包含 "+i(t.rowCount)+" 条数据",1)):v("",!0),t.entryCount&&t.entryCount>0?(a(),n("div",Js,"压缩包内共 "+i(t.entryCount)+" 个拆分文件 ",1)):v("",!0),t.entries&&t.entries.length?(a(),n("div",Ls," 压缩包内容:"+i(A(t.entries)),1)):v("",!0),t.error?(a(),n("div",qs,"错误信息:"+i(t.error),1)):v("",!0)]),e("div",Os,[e("span",{class:x(["status",t.success?"success":"failed"])},i(t.success?"已完成":"失败"),3),t.success&&(t.downloadUrl||t.resultId)?(a(),n("button",{key:0,type:"button",class:"download",onClick:o=>z(t)}," 下载压缩包 ",8,Ws)):v("",!0),t.resultId?(a(),n("button",{key:1,type:"button",class:"btn-delete",onClick:o=>j(t.resultId)}," 删除 ",8,Gs)):v("",!0)])]))),128))]))])])])])]))}}),Xs=ls(Qs,[["__scopeId","data-v-77886e3c"]]);as(Xs).use(ns).mount("#app"); +import{d as L,o as q,a,c as n,b as O,B as W,e,F as S,r as E,t as i,f as v,n as x,w as k,x as V,H as M,g as d,h as G,i as $,E as r,I as Q,J as X,p as Y,v as Z,K as ss,L as es,s as ts,_ as ls,q as as,u as ns}from"./java-modules-B8c-YG5x.js";import{e as os}from"./brand-COze15GJ.js";const is={class:"page-shell module-page"},rs={class:"main-content"},us={class:"left-panel"},ds={class:"upload-zone"},cs={class:"selected-files clean-placeholder split-selected-files"},ps={key:0,class:"more-line"},vs={key:1},fs={class:"option-group column-option-group"},_s={class:"column-toolbar"},ms={class:"column-count"},ys={class:"column-actions"},gs={key:0,class:"column-grid"},hs=["value"],bs={key:1,class:"empty-column-state"},ws={class:"option-group"},ks={class:"radio-item active"},Cs={class:"desc"},Ss={class:"option-group"},xs={class:"option-group"},Fs={key:0,class:"split-input-card"},Ps={key:1,class:"split-input-card"},Es={class:"run-row"},$s=["disabled"],Is={class:"loading-msg"},Rs={class:"right-panel"},Bs={class:"task-list-wrap"},Us={class:"clean-result-summary"},Vs={class:"summary-card"},Ms={class:"summary-card"},Ts={class:"summary-card"},Ds={class:"result-list-wrap"},Hs={key:0,class:"empty-tasks"},Ks={key:1,class:"task-list clean-result-list"},Ns={class:"left split-result-main"},js=["title"],As={key:0,class:"files"},zs={key:1,class:"time"},Js={key:2,class:"files"},Ls={key:3,class:"files split-entry-list"},qs={key:4,class:"files"},Os={class:"task-right split-result-actions"},Ws=["onClick"],Gs=["onClick"],Qs=L({__name:"BrandSplitTab",setup(Ys){const f=d([]),C=d(""),c=d([]),_=d([]),p=d([]),I=d(0),u=d("rows_per_file"),m=d(2e3),y=d(5),g=d(!1),h=d([]),b=d({total:0,successCount:0,failedCount:0,items:[]}),F=G(()=>f.value.slice(0,8));function T(l){b.value={total:l.length,successCount:l.filter(s=>s.success).length,failedCount:l.filter(s=>!s.success).length,items:l}}async function R(l){const s=$();if(!s?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传桥接能力");const t=[];for(const o of l){const U=typeof o=="string"?o:o.absolutePath,J=typeof o=="string"?void 0:o.relativePath,w=await s.upload_file_to_java(U,J);if(!w?.success||!w.data)throw new Error(w?.error||w?.message||`上传失败:${U}`);t.push(w.data)}return t}async function B(l){const s=await Y(l);_.value=s.headers||[],p.value=[...s.headers||[]],I.value=s.totalRows||0}async function D(l,s){f.value=l,C.value="",c.value=await R(l),c.value.length>0&&await B(c.value[0].fileKey),r.success(s)}async function H(){const l=$();if(!l?.select_brand_xlsx_files){r.warning("当前环境不支持文件选择,请在本机客户端中打开");return}try{const s=await l.select_brand_xlsx_files();if(!s?.length)return;await D(s,`已选择 ${s.length} 个待拆分文件`)}catch(s){r.error(s instanceof Error?s.message:"选择失败")}}async function K(){const l=$();if(!l?.select_brand_folder){r.warning("当前环境不支持文件夹选择,请在本机客户端中打开");return}try{const s=await l.select_brand_folder();if(!s)return;C.value=s.split(/[/\\]/).filter(Boolean).pop()||"";const t=await os(s);if(t.success&&t.items?.length){f.value=t.items.map(o=>o.relativePath),c.value=await R(t.items),c.value.length>0&&await B(c.value[0].fileKey),r.success(`已选择文件夹内 ${t.items.length} 个 xlsx 文件`);return}r.warning(t.error||"该文件夹下没有 xlsx 文件")}catch(s){r.error(s instanceof Error?s.message:"选择失败")}}async function N(){if(!c.value.length){r.warning("请先选择待拆分 Excel 文件或文件夹");return}if(!p.value.length){r.warning("请至少选择一列保留列");return}if(u.value==="rows_per_file"&&(!m.value||m.value<=0)){r.warning("请输入有效的每份条数");return}if(u.value==="parts"&&(!y.value||y.value<=0)){r.warning("请输入有效的拆分份数");return}try{g.value=!0;const l=await Q({files:c.value.map(s=>({fileKey:s.fileKey,originalFilename:s.originalFilename,relativePath:s.relativePath})),selectedColumns:p.value,splitMode:u.value,rowsPerFile:u.value==="rows_per_file"&&m.value||void 0,parts:u.value==="parts"&&y.value||void 0,archiveName:c.value.some(s=>!!s.relativePath)&&C.value?C.value:void 0});b.value=l,h.value=l.items||[],await P(),r.success("数据拆分完成")}catch(l){r.error(l instanceof Error?l.message:"数据拆分失败")}finally{g.value=!1}}async function P(){try{const l=await X();h.value=l.items||[],T(h.value)}catch{}}async function j(l){try{await ss(l),await P(),r.success("已删除")}catch(s){r.error(s instanceof Error?s.message:"删除失败")}}function A(l){const s=l.slice(0,4).map(o=>o.rowCount!==void 0?`${o.filename}(${o.rowCount}条)`:o.filename);return l.length-s.length>0?`${s.join("、")} 等 ${l.length} 个文件`:s.join("、")}async function z(l){const s=l.downloadUrl||(l.resultId?es(l.resultId):"");if(!s){r.warning("当前结果没有下载地址");return}const t=l.outputFilename||`${new Date().toISOString().slice(0,10).replace(/-/g,"")}.zip`,o=await ts(s,t,l.resultId?`split:${l.resultId}`:void 0);o.success?r.success(`已保存:${o.path||t}`):o.error&&o.error!=="用户取消"&&r.error(o.error)}return q(()=>{P().catch(()=>{})}),(l,s)=>(a(),n("div",is,[O(W,{active:"split"}),e("div",rs,[e("aside",us,[s[14]||(s[14]=e("div",{class:"section-title"},"选择文件",-1)),e("div",ds,[s[7]||(s[7]=e("div",{class:"hint"},"选择需要拆分的 Excel 文件或文件夹,按规则拆成多个 Excel 文件。",-1)),e("div",{class:"btns"},[e("button",{type:"button",class:"opt-btn",onClick:H},"选择 Excel 文件"),e("button",{type:"button",class:"opt-btn",onClick:K},"选择文件夹")]),e("div",cs,[f.value.length?(a(),n(S,{key:0},[(a(!0),n(S,null,E(F.value,t=>(a(),n("span",{key:t},i(t),1))),128)),f.value.length>F.value.length?(a(),n("span",ps," 还有 "+i(f.value.length-F.value.length)+" 个文件未展开显示 ",1)):v("",!0)],64)):(a(),n("span",vs,"暂未选择待拆分文件"))])]),s[15]||(s[15]=e("div",{class:"section-title"},"保留列设置",-1)),e("div",fs,[e("div",_s,[e("span",ms,"已选择 "+i(p.value.length)+" / "+i(_.value.length)+" 列",1),e("div",ys,[e("button",{type:"button",class:"opt-btn small",onClick:s[0]||(s[0]=t=>p.value=[..._.value])},"全选"),e("button",{type:"button",class:"opt-btn small",onClick:s[1]||(s[1]=t=>p.value=[])},"清空")])]),_.value.length?(a(),n("div",gs,[(a(!0),n(S,null,E(_.value,t=>(a(),n("label",{key:t,class:x(["column-item",{active:p.value.includes(t)}])},[k(e("input",{"onUpdate:modelValue":s[2]||(s[2]=o=>p.value=o),type:"checkbox",value:t},null,8,hs),[[Z,p.value]]),e("span",null,i(t),1)],2))),128))])):(a(),n("div",bs,"请选择 Excel 文件后读取表头并填充可保留列"))]),s[16]||(s[16]=e("div",{class:"section-title"},"总条数",-1)),e("div",ws,[e("label",ks,[s[9]||(s[9]=e("input",{type:"checkbox",checked:"",disabled:""},null,-1)),e("div",null,[s[8]||(s[8]=e("span",{class:"label"},"当前数据总条数",-1)),e("div",Cs,i(I.value)+" 条(不含表头)",1)])])]),s[17]||(s[17]=e("div",{class:"section-title"},"拆分模式",-1)),e("div",Ss,[e("label",{class:x(["radio-item",{active:u.value==="rows_per_file"}])},[k(e("input",{"onUpdate:modelValue":s[3]||(s[3]=t=>u.value=t),type:"radio",value:"rows_per_file",name:"split-mode"},null,512),[[V,u.value]]),s[10]||(s[10]=e("div",null,[e("span",{class:"label"},"按每份条数"),e("div",{class:"desc"},"例如每份 2000 条,最后一份放剩余数据")],-1))],2),e("label",{class:x(["radio-item",{active:u.value==="parts"}])},[k(e("input",{"onUpdate:modelValue":s[4]||(s[4]=t=>u.value=t),type:"radio",value:"parts",name:"split-mode"},null,512),[[V,u.value]]),s[11]||(s[11]=e("div",null,[e("span",{class:"label"},"按份数平均拆分"),e("div",{class:"desc"},"例如拆 5 份,按总条数尽量平均分配")],-1))],2)]),s[18]||(s[18]=e("div",{class:"section-title"},"拆分参数",-1)),e("div",xs,[u.value==="rows_per_file"?(a(),n("label",Fs,[s[12]||(s[12]=e("span",{class:"label"},"每份条数",-1)),k(e("input",{"onUpdate:modelValue":s[5]||(s[5]=t=>m.value=t),class:"split-number-input",type:"number",min:"1",placeholder:"例如 2000"},null,512),[[M,m.value,void 0,{number:!0}]])])):(a(),n("label",Ps,[s[13]||(s[13]=e("span",{class:"label"},"拆分份数",-1)),k(e("input",{"onUpdate:modelValue":s[6]||(s[6]=t=>y.value=t),class:"split-number-input",type:"number",min:"1",placeholder:"例如 5"},null,512),[[M,y.value,void 0,{number:!0}]])]))]),e("div",Es,[e("button",{type:"button",class:"btn-run",disabled:g.value,onClick:N},i(g.value?"拆分中...":"开始拆分"),9,$s),e("span",Is,i(g.value?"正在拆分并上传结果,请稍候…":"选择文件、保留列和拆分规则后即可执行拆分,结果会显示在右侧供下载"),1)])]),e("section",Rs,[s[23]||(s[23]=e("div",{class:"panel-header"},"拆分结果",-1)),e("div",Bs,[e("div",Us,[e("div",Vs,[s[19]||(s[19]=e("span",{class:"summary-label"},"已处理文件",-1)),e("strong",null,i(b.value.total),1)]),e("div",Ms,[s[20]||(s[20]=e("span",{class:"summary-label"},"成功结果",-1)),e("strong",null,i(b.value.successCount),1)]),e("div",Ts,[s[21]||(s[21]=e("span",{class:"summary-label"},"失败文件",-1)),e("strong",null,i(b.value.failedCount),1)])]),e("div",Ds,[s[22]||(s[22]=e("div",{class:"result-list-header"},[e("span",null,"拆分结果压缩包列表")],-1)),h.value.length===0?(a(),n("div",Hs," 暂无拆分结果,完成数据拆分后会在这里展示压缩包文件 ")):(a(),n("ul",Ks,[(a(!0),n(S,null,E(h.value,t=>(a(),n("li",{key:`${t.resultId||t.outputFilename||t.sourceFilename}-${t.rowCount||0}`,class:"task-item split-result-item"},[e("div",Ns,[e("span",{class:"id",title:t.sourceFilename},i(t.sourceFilename||"-"),9,js),t.outputFilename?(a(),n("div",As,"压缩包文件:"+i(t.outputFilename),1)):v("",!0),t.rowCount!==void 0?(a(),n("div",zs,"压缩包共包含 "+i(t.rowCount)+" 条数据",1)):v("",!0),t.entryCount&&t.entryCount>0?(a(),n("div",Js,"压缩包内共 "+i(t.entryCount)+" 个拆分文件 ",1)):v("",!0),t.entries&&t.entries.length?(a(),n("div",Ls," 压缩包内容:"+i(A(t.entries)),1)):v("",!0),t.error?(a(),n("div",qs,"错误信息:"+i(t.error),1)):v("",!0)]),e("div",Os,[e("span",{class:x(["status",t.success?"success":"failed"])},i(t.success?"已完成":"失败"),3),t.success&&(t.downloadUrl||t.resultId)?(a(),n("button",{key:0,type:"button",class:"download",onClick:o=>z(t)}," 下载压缩包 ",8,Ws)):v("",!0),t.resultId?(a(),n("button",{key:1,type:"button",class:"btn-delete",onClick:o=>j(t.resultId)}," 删除 ",8,Gs)):v("",!0)])]))),128))]))])])])])]))}}),Xs=ls(Qs,[["__scopeId","data-v-77886e3c"]]);as(Xs).use(ns).mount("#app"); diff --git a/app/assets/zh-cn-z8KAT-CE.js b/app/assets/zh-cn-CscLo6na.js similarity index 98% rename from app/assets/zh-cn-z8KAT-CE.js rename to app/assets/zh-cn-CscLo6na.js index dd21ce1..4988f98 100644 --- a/app/assets/zh-cn-z8KAT-CE.js +++ b/app/assets/zh-cn-CscLo6na.js @@ -1 +1 @@ -import{bA as m}from"./java-modules-DzYrjxib.js";var _={name:"zh-cn",el:{breadcrumb:{label:"面包屑"},colorpicker:{confirm:"确定",clear:"清空",defaultLabel:"颜色选择器",description:"当前颜色 {color},按 Enter 键选择新颜色",alphaLabel:"选择透明度的值",alphaDescription:"透明度 {alpha}, 当前颜色 {color}",hueLabel:"选择色相值",hueDescription:"色相 {hue}, 当前颜色 {color}",svLabel:"选择饱和度与明度的值",svDescription:"饱和度 {saturation}, 明度 {brightness}, 当前颜色 {color}",predefineDescription:"选择 {value} 作为颜色"},datepicker:{now:"此刻",today:"今天",cancel:"取消",clear:"清空",confirm:"确定",dateTablePrompt:"使用方向键与 Enter 键可选择日期",monthTablePrompt:"使用方向键与 Enter 键可选择月份",yearTablePrompt:"使用方向键与 Enter 键可选择年份",selectedDate:"已选日期",selectDate:"选择日期",selectTime:"选择时间",startDate:"开始日期",startTime:"开始时间",endDate:"结束日期",endTime:"结束时间",prevYear:"前一年",nextYear:"后一年",prevMonth:"上个月",nextMonth:"下个月",year:"年",month1:"1 月",month2:"2 月",month3:"3 月",month4:"4 月",month5:"5 月",month6:"6 月",month7:"7 月",month8:"8 月",month9:"9 月",month10:"10 月",month11:"11 月",month12:"12 月",weeks:{sun:"日",mon:"一",tue:"二",wed:"三",thu:"四",fri:"五",sat:"六"},weeksFull:{sun:"星期日",mon:"星期一",tue:"星期二",wed:"星期三",thu:"星期四",fri:"星期五",sat:"星期六"},months:{jan:"一月",feb:"二月",mar:"三月",apr:"四月",may:"五月",jun:"六月",jul:"七月",aug:"八月",sep:"九月",oct:"十月",nov:"十一月",dec:"十二月"}},inputNumber:{decrease:"减少数值",increase:"增加数值"},select:{loading:"加载中",noMatch:"无匹配数据",noData:"无数据",placeholder:"请选择"},mention:{loading:"加载中"},dropdown:{toggleDropdown:"切换下拉选项"},cascader:{noMatch:"无匹配数据",loading:"加载中",placeholder:"请选择",noData:"暂无数据"},pagination:{goto:"前往",pagesize:"条/页",total:"共 {total} 条",pageClassifier:"页",page:"页",prev:"上一页",next:"下一页",currentPage:"第 {pager} 页",prevPages:"向前 {pager} 页",nextPages:"向后 {pager} 页",deprecationWarning:"你使用了一些已被废弃的用法,请参考 el-pagination 的官方文档"},dialog:{close:"关闭此对话框"},drawer:{close:"关闭此对话框"},messagebox:{title:"提示",confirm:"确定",cancel:"取消",error:"输入的数据不合法!",close:"关闭此对话框"},upload:{deleteTip:"按 Delete 键可删除",delete:"删除",preview:"查看图片",continue:"继续上传"},slider:{defaultLabel:"滑块介于 {min} 至 {max}",defaultRangeStartLabel:"选择起始值",defaultRangeEndLabel:"选择结束值"},table:{emptyText:"暂无数据",confirmFilter:"筛选",resetFilter:"重置",clearFilter:"全部",sumText:"合计",selectAllLabel:"选择所有行",selectRowLabel:"选择当前行",expandRowLabel:"展开当前行",collapseRowLabel:"收起当前行",sortLabel:"按 {column} 排序",filterLabel:"按 {column} 过滤"},tag:{close:"关闭此标签"},tour:{next:"下一步",previous:"上一步",finish:"结束导览",close:"关闭此对话框"},tree:{emptyText:"暂无数据"},transfer:{noMatch:"无匹配数据",noData:"无数据",titles:["列表 1","列表 2"],filterPlaceholder:"请输入搜索内容",noCheckedFormat:"共 {total} 项",hasCheckedFormat:"已选 {checked}/{total} 项"},image:{error:"加载失败"},pageHeader:{title:"返回"},popconfirm:{confirmButtonText:"确定",cancelButtonText:"取消"},carousel:{leftArrow:"上一张幻灯片",rightArrow:"下一张幻灯片",indicator:"幻灯片切换至索引 {index}"}}},a={exports:{}},d=a.exports,i;function p(){return i||(i=1,(function(s,u){(function(n,r){s.exports=r(m())})(d,(function(n){function r(e){return e&&typeof e=="object"&&"default"in e?e:{default:e}}var c=r(n),l={name:"zh-cn",weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"周日_周一_周二_周三_周四_周五_周六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),ordinal:function(e,o){return o==="W"?e+"周":e+"日"},weekStart:1,yearStart:4,formats:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日Ah点mm分",LLLL:"YYYY年M月D日ddddAh点mm分",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},relativeTime:{future:"%s内",past:"%s前",s:"几秒",m:"1 分钟",mm:"%d 分钟",h:"1 小时",hh:"%d 小时",d:"1 天",dd:"%d 天",M:"1 个月",MM:"%d 个月",y:"1 年",yy:"%d 年"},meridiem:function(e,o){var t=100*e+o;return t<600?"凌晨":t<900?"早上":t<1100?"上午":t<1300?"中午":t<1800?"下午":"晚上"}};return c.default.locale(l,null,!0),l}))})(a)),a.exports}p();export{_ as z}; +import{bA as m}from"./java-modules-B8c-YG5x.js";var _={name:"zh-cn",el:{breadcrumb:{label:"面包屑"},colorpicker:{confirm:"确定",clear:"清空",defaultLabel:"颜色选择器",description:"当前颜色 {color},按 Enter 键选择新颜色",alphaLabel:"选择透明度的值",alphaDescription:"透明度 {alpha}, 当前颜色 {color}",hueLabel:"选择色相值",hueDescription:"色相 {hue}, 当前颜色 {color}",svLabel:"选择饱和度与明度的值",svDescription:"饱和度 {saturation}, 明度 {brightness}, 当前颜色 {color}",predefineDescription:"选择 {value} 作为颜色"},datepicker:{now:"此刻",today:"今天",cancel:"取消",clear:"清空",confirm:"确定",dateTablePrompt:"使用方向键与 Enter 键可选择日期",monthTablePrompt:"使用方向键与 Enter 键可选择月份",yearTablePrompt:"使用方向键与 Enter 键可选择年份",selectedDate:"已选日期",selectDate:"选择日期",selectTime:"选择时间",startDate:"开始日期",startTime:"开始时间",endDate:"结束日期",endTime:"结束时间",prevYear:"前一年",nextYear:"后一年",prevMonth:"上个月",nextMonth:"下个月",year:"年",month1:"1 月",month2:"2 月",month3:"3 月",month4:"4 月",month5:"5 月",month6:"6 月",month7:"7 月",month8:"8 月",month9:"9 月",month10:"10 月",month11:"11 月",month12:"12 月",weeks:{sun:"日",mon:"一",tue:"二",wed:"三",thu:"四",fri:"五",sat:"六"},weeksFull:{sun:"星期日",mon:"星期一",tue:"星期二",wed:"星期三",thu:"星期四",fri:"星期五",sat:"星期六"},months:{jan:"一月",feb:"二月",mar:"三月",apr:"四月",may:"五月",jun:"六月",jul:"七月",aug:"八月",sep:"九月",oct:"十月",nov:"十一月",dec:"十二月"}},inputNumber:{decrease:"减少数值",increase:"增加数值"},select:{loading:"加载中",noMatch:"无匹配数据",noData:"无数据",placeholder:"请选择"},mention:{loading:"加载中"},dropdown:{toggleDropdown:"切换下拉选项"},cascader:{noMatch:"无匹配数据",loading:"加载中",placeholder:"请选择",noData:"暂无数据"},pagination:{goto:"前往",pagesize:"条/页",total:"共 {total} 条",pageClassifier:"页",page:"页",prev:"上一页",next:"下一页",currentPage:"第 {pager} 页",prevPages:"向前 {pager} 页",nextPages:"向后 {pager} 页",deprecationWarning:"你使用了一些已被废弃的用法,请参考 el-pagination 的官方文档"},dialog:{close:"关闭此对话框"},drawer:{close:"关闭此对话框"},messagebox:{title:"提示",confirm:"确定",cancel:"取消",error:"输入的数据不合法!",close:"关闭此对话框"},upload:{deleteTip:"按 Delete 键可删除",delete:"删除",preview:"查看图片",continue:"继续上传"},slider:{defaultLabel:"滑块介于 {min} 至 {max}",defaultRangeStartLabel:"选择起始值",defaultRangeEndLabel:"选择结束值"},table:{emptyText:"暂无数据",confirmFilter:"筛选",resetFilter:"重置",clearFilter:"全部",sumText:"合计",selectAllLabel:"选择所有行",selectRowLabel:"选择当前行",expandRowLabel:"展开当前行",collapseRowLabel:"收起当前行",sortLabel:"按 {column} 排序",filterLabel:"按 {column} 过滤"},tag:{close:"关闭此标签"},tour:{next:"下一步",previous:"上一步",finish:"结束导览",close:"关闭此对话框"},tree:{emptyText:"暂无数据"},transfer:{noMatch:"无匹配数据",noData:"无数据",titles:["列表 1","列表 2"],filterPlaceholder:"请输入搜索内容",noCheckedFormat:"共 {total} 项",hasCheckedFormat:"已选 {checked}/{total} 项"},image:{error:"加载失败"},pageHeader:{title:"返回"},popconfirm:{confirmButtonText:"确定",cancelButtonText:"取消"},carousel:{leftArrow:"上一张幻灯片",rightArrow:"下一张幻灯片",indicator:"幻灯片切换至索引 {index}"}}},a={exports:{}},d=a.exports,i;function p(){return i||(i=1,(function(s,u){(function(n,r){s.exports=r(m())})(d,(function(n){function r(e){return e&&typeof e=="object"&&"default"in e?e:{default:e}}var c=r(n),l={name:"zh-cn",weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"周日_周一_周二_周三_周四_周五_周六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),ordinal:function(e,o){return o==="W"?e+"周":e+"日"},weekStart:1,yearStart:4,formats:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日Ah点mm分",LLLL:"YYYY年M月D日ddddAh点mm分",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},relativeTime:{future:"%s内",past:"%s前",s:"几秒",m:"1 分钟",mm:"%d 分钟",h:"1 小时",hh:"%d 小时",d:"1 天",dd:"%d 天",M:"1 个月",MM:"%d 个月",y:"1 年",yy:"%d 年"},meridiem:function(e,o){var t=100*e+o;return t<600?"凌晨":t<900?"早上":t<1100?"上午":t<1300?"中午":t<1800?"下午":"晚上"}};return c.default.locale(l,null,!0),l}))})(a)),a.exports}p();export{_ as z}; diff --git a/app/new_web_source/convert.html b/app/new_web_source/convert.html index 50c00b1..623cb9c 100644 --- a/app/new_web_source/convert.html +++ b/app/new_web_source/convert.html @@ -5,8 +5,8 @@ 格式转换 - 数富AI - - + + diff --git a/app/new_web_source/dedupe.html b/app/new_web_source/dedupe.html index 10ef3c6..7aaadd0 100644 --- a/app/new_web_source/dedupe.html +++ b/app/new_web_source/dedupe.html @@ -5,8 +5,8 @@ 数据去重 - 数富AI - - + + diff --git a/app/new_web_source/delete-brand.html b/app/new_web_source/delete-brand.html index 70cc85f..d9e6338 100644 --- a/app/new_web_source/delete-brand.html +++ b/app/new_web_source/delete-brand.html @@ -5,8 +5,8 @@ 删除品牌 - 数富AI - - + + diff --git a/app/new_web_source/split.html b/app/new_web_source/split.html index d18c08d..8455304 100644 --- a/app/new_web_source/split.html +++ b/app/new_web_source/split.html @@ -5,8 +5,8 @@ 数据拆分 - 数富AI - - + + diff --git a/backend-java/src/main/java/com/nanri/aiimage/modules/collectdata/model/dto/CollectDataFiltersDto.java b/backend-java/src/main/java/com/nanri/aiimage/modules/collectdata/model/dto/CollectDataFiltersDto.java index a8f4553..2a3ab76 100644 --- a/backend-java/src/main/java/com/nanri/aiimage/modules/collectdata/model/dto/CollectDataFiltersDto.java +++ b/backend-java/src/main/java/com/nanri/aiimage/modules/collectdata/model/dto/CollectDataFiltersDto.java @@ -1,6 +1,7 @@ package com.nanri.aiimage.modules.collectdata.model.dto; import io.swagger.v3.oas.annotations.media.Schema; +import com.fasterxml.jackson.annotation.JsonAlias; import lombok.Data; import java.math.BigDecimal; @@ -14,8 +15,16 @@ public class CollectDataFiltersDto { @Schema(description = "金额(手动输入),可为空", example = "59.99") private BigDecimal amount; - @Schema(description = "排名(手动输入),可为空", example = "100000") - private Integer rank; + @JsonAlias({"min_amount"}) + @Schema(description = "最小金额,可为空", example = "10.00") + private BigDecimal minAmount; + + @JsonAlias({"max_amount"}) + @Schema(description = "最大金额,可为空", example = "59.99") + private BigDecimal maxAmount; + + @Schema(description = "是否启用排名条件") + private Boolean rank; @Schema(description = "是否包含 FBA 商品") private Boolean fba; @@ -25,4 +34,8 @@ public class CollectDataFiltersDto { @Schema(description = "国家代码列表,按用户拖拽顺序保存", example = "[\"DE\",\"UK\"]") private List countryCodes = new ArrayList<>(); + + @JsonAlias({"country_code"}) + @Schema(description = "单选国家代码,采集数据页面当前只选择一个国家", example = "DE") + private String countryCode; } diff --git a/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/client/SimilarAsinCozeClient.java b/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/client/SimilarAsinCozeClient.java index f04f2d2..4cec407 100644 --- a/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/client/SimilarAsinCozeClient.java +++ b/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/client/SimilarAsinCozeClient.java @@ -42,6 +42,10 @@ public class SimilarAsinCozeClient { private volatile RestClient sharedRestClient; public List inspect(List rows, String prompt, String apiKey) { + return inspect(rows, prompt, apiKey, false); + } + + public List inspect(List rows, String prompt, String apiKey, boolean imgSwitch) { if (rows == null || rows.isEmpty()) { return List.of(); } @@ -50,7 +54,7 @@ public class SimilarAsinCozeClient { return rows.stream().map(this::copy).toList(); } try { - return inspectWithFallback(rows, prompt, apiKey); + return inspectWithFallback(rows, prompt, apiKey, imgSwitch); } catch (Exception ex) { String failureMessage = failureMessage(ex); log.warn("[similar-asin] coze batch failed size={} err={}", rows.size(), failureMessage); @@ -59,15 +63,20 @@ public class SimilarAsinCozeClient { } public CozeSubmitResponse submitWorkflow(List rows, String prompt, String apiKey) throws Exception { - return submitWorkflow(rows, prompt, apiKey, nextCredential()); + return submitWorkflow(rows, prompt, apiKey, false, nextCredential()); + } + + public CozeSubmitResponse submitWorkflow(List rows, String prompt, String apiKey, boolean imgSwitch) throws Exception { + return submitWorkflow(rows, prompt, apiKey, imgSwitch, nextCredential()); } public CozeSubmitResponse submitWorkflow(List rows, String prompt, String apiKey, + boolean imgSwitch, CozeCredentialRef credential) throws Exception { CozeCredentialRef resolvedCredential = resolveCredential(credential); - JsonNode submitRoot = objectMapper.readTree(postWorkflow(rows, prompt, apiKey, resolvedCredential)); + JsonNode submitRoot = objectMapper.readTree(postWorkflow(rows, prompt, apiKey, imgSwitch, resolvedCredential)); ensureSuccess(submitRoot); return new CozeSubmitResponse( extractExecuteId(submitRoot), @@ -109,12 +118,12 @@ public class SimilarAsinCozeClient { return rows.stream().map(this::copy).map(row -> markFailed(row, failureMessage)).toList(); } - private List inspectWithFallback(List rows, String prompt, String apiKey) { + private List inspectWithFallback(List rows, String prompt, String apiKey, boolean imgSwitch) { try { if (rows.size() == 1) { - return inspectSingleRowWithRetry(rows, prompt, apiKey); + return inspectSingleRowWithRetry(rows, prompt, apiKey, imgSwitch); } - InspectAttempt attempt = inspectOnce(rows, prompt, apiKey); + InspectAttempt attempt = inspectOnce(rows, prompt, apiKey, imgSwitch); if (attempt.resolvedCount() < rows.size()) { throw new PartialCozeResultException(attempt.resolvedCount(), rows.size(), attempt.rawResultCount()); } @@ -125,17 +134,17 @@ public class SimilarAsinCozeClient { log.warn("[similar-asin] coze batch fallback split size={} left={} right={} err={}", rows.size(), middle, rows.size() - middle, failureMessage(ex)); List merged = new ArrayList<>(rows.size()); - merged.addAll(inspectPartitionWithFailureFallback(rows.subList(0, middle), prompt, apiKey)); - merged.addAll(inspectPartitionWithFailureFallback(rows.subList(middle, rows.size()), prompt, apiKey)); + merged.addAll(inspectPartitionWithFailureFallback(rows.subList(0, middle), prompt, apiKey, imgSwitch)); + merged.addAll(inspectPartitionWithFailureFallback(rows.subList(middle, rows.size()), prompt, apiKey, imgSwitch)); return merged; } throw propagate(ex); } } - private List inspectPartitionWithFailureFallback(List rows, String prompt, String apiKey) { + private List inspectPartitionWithFailureFallback(List rows, String prompt, String apiKey, boolean imgSwitch) { try { - return inspectWithFallback(rows, prompt, apiKey); + return inspectWithFallback(rows, prompt, apiKey, imgSwitch); } catch (Exception ex) { String failureMessage = failureMessage(ex); log.warn("[similar-asin] coze partition failed size={} err={}", rows.size(), failureMessage); @@ -143,12 +152,12 @@ public class SimilarAsinCozeClient { } } - private List inspectSingleRowWithRetry(List rows, String prompt, String apiKey) throws Exception { + private List inspectSingleRowWithRetry(List rows, String prompt, String apiKey, boolean imgSwitch) throws Exception { SimilarAsinResultRowDto row = rows.getFirst(); PartialCozeResultException lastFailure = null; for (int attemptIndex = 1; attemptIndex <= 3; attemptIndex++) { try { - InspectAttempt attempt = inspectOnce(rows, prompt, apiKey); + InspectAttempt attempt = inspectOnce(rows, prompt, apiKey, imgSwitch); if (attempt.resolvedCount() == rows.size()) { return attempt.mergedRows(); } @@ -179,16 +188,16 @@ public class SimilarAsinCozeClient { throw lastFailure == null ? new PartialCozeResultException(0, rows.size(), 0) : lastFailure; } - private InspectAttempt inspectOnce(List rows, String prompt, String apiKey) throws Exception { - String raw = runWorkflowAsyncAndWait(rows, prompt, apiKey); + private InspectAttempt inspectOnce(List rows, String prompt, String apiKey, boolean imgSwitch) throws Exception { + String raw = runWorkflowAsyncAndWait(rows, prompt, apiKey, imgSwitch); List results = parseResults(raw); List merged = mergeRows(rows, results); return new InspectAttempt(raw, merged, resolvedCount(merged), results.size()); } - private String runWorkflowAsyncAndWait(List rows, String prompt, String apiKey) throws Exception { + private String runWorkflowAsyncAndWait(List rows, String prompt, String apiKey, boolean imgSwitch) throws Exception { CozeCredentialRef credential = nextCredential(); - JsonNode submitRoot = objectMapper.readTree(postWorkflow(rows, prompt, apiKey, credential)); + JsonNode submitRoot = objectMapper.readTree(postWorkflow(rows, prompt, apiKey, imgSwitch, credential)); ensureSuccess(submitRoot); String immediateData = extractResultDataText(submitRoot); @@ -232,8 +241,9 @@ public class SimilarAsinCozeClient { private String postWorkflow(List rows, String prompt, String apiKey, + boolean imgSwitch, CozeCredentialRef credential) { - Map parameters = buildParameters(rows, prompt, apiKey); + Map parameters = buildParameters(rows, prompt, apiKey, imgSwitch); Map body = new LinkedHashMap<>(); body.put("workflow_id", credential.workflowId()); body.put("parameters", parameters); @@ -354,7 +364,7 @@ public class SimilarAsinCozeClient { return credentials; } - private Map buildParameters(List rows, String prompt, String apiKey) { + private Map buildParameters(List rows, String prompt, String apiKey, boolean imgSwitch) { List asins = rows.stream().map(row -> safeText(row.getAsin())).toList(); List titles = rows.stream().map(row -> safeText(firstNonBlank(row.getTitle(), row.getAsin()))).toList(); List skus = rows.stream().map(row -> safeText(row.getSku())).toList(); @@ -375,6 +385,7 @@ public class SimilarAsinCozeClient { if (includeLegacyApiKey && apiKey != null && !apiKey.isBlank()) { parameters.put("api_key", apiKey.trim()); } + parameters.put("img_switch", imgSwitch); return parameters; } diff --git a/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/model/dto/SimilarAsinParseRequest.java b/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/model/dto/SimilarAsinParseRequest.java index b8e354f..cc0c81e 100644 --- a/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/model/dto/SimilarAsinParseRequest.java +++ b/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/model/dto/SimilarAsinParseRequest.java @@ -32,4 +32,9 @@ public class SimilarAsinParseRequest { @Schema(description = "传递给 Coze workflow parameters.api_key 的任务级密钥。") @NotBlank(message = "密钥不能为空") private String apiKey; + + @JsonProperty("img_switch") + @JsonAlias({"imgSwitch"}) + @Schema(description = "传递给 Coze workflow parameters.img_switch 的图片检测开关,true 为开启,false 为关闭。") + private Boolean imgSwitch = Boolean.FALSE; } diff --git a/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/model/dto/SimilarAsinParsedPayloadDto.java b/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/model/dto/SimilarAsinParsedPayloadDto.java index 7625b37..8231d76 100644 --- a/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/model/dto/SimilarAsinParsedPayloadDto.java +++ b/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/model/dto/SimilarAsinParsedPayloadDto.java @@ -17,6 +17,9 @@ public class SimilarAsinParsedPayloadDto { @Schema(description = "传递给 Coze workflow parameters.api_key 的任务级密钥") private String apiKey; + @Schema(description = "传递给 Coze workflow parameters.img_switch 的图片检测开关") + private Boolean imgSwitch = Boolean.FALSE; + @Schema(description = "本次解析的源文件列表") private List sourceFiles = new ArrayList<>(); diff --git a/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/model/vo/SimilarAsinParseVo.java b/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/model/vo/SimilarAsinParseVo.java index 5a126af..ccae28d 100644 --- a/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/model/vo/SimilarAsinParseVo.java +++ b/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/model/vo/SimilarAsinParseVo.java @@ -33,6 +33,9 @@ public class SimilarAsinParseVo { @Schema(description = "本任务最终使用的 AI 提示词") private String aiPrompt; + @Schema(description = "图片检测开关,true 为开启,false 为关闭") + private Boolean imgSwitch = Boolean.FALSE; + @Schema(description = "兼容旧前端的平铺有效行列表,现为全部有效行") private List items = new ArrayList<>(); diff --git a/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/service/SimilarAsinTaskService.java b/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/service/SimilarAsinTaskService.java index 4e34e58..3f462ce 100644 --- a/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/service/SimilarAsinTaskService.java +++ b/backend-java/src/main/java/com/nanri/aiimage/modules/similarasin/service/SimilarAsinTaskService.java @@ -401,11 +401,11 @@ public class SimilarAsinTaskService { String aggregateScopeKey = buildAggregateScopeKey(sourceFiles); String sourceScopeHash = DigestUtil.sha256Hex(aggregateScopeKey); - String parsedPayload = buildParsedPayloadJson(request.getAiPrompt(), request.getApiKey(), sourceFiles, mergedHeaders, groups, allRows); + String parsedPayload = buildParsedPayloadJson(request.getAiPrompt(), request.getApiKey(), request.getImgSwitch(), sourceFiles, mergedHeaders, groups, allRows); long payloadBuiltAt = System.nanoTime(); String parsedPayloadPointer = storeParsedPayload(task.getId(), sourceScopeHash, parsedPayload); long payloadStoredAt = System.nanoTime(); - task.setResultJson(buildTaskResultJson(request.getAiPrompt(), request.getApiKey(), sourceFiles, parsedPayloadPointer)); + task.setResultJson(buildTaskResultJson(request.getAiPrompt(), request.getApiKey(), request.getImgSwitch(), sourceFiles, parsedPayloadPointer)); task.setUpdatedAt(LocalDateTime.now()); fileTaskMapper.updateById(task); @@ -444,6 +444,7 @@ public class SimilarAsinTaskService { vo.setDroppedRows(droppedRows); vo.setGroupCount(groups.size()); vo.setAiPrompt(normalize(request.getAiPrompt())); + vo.setImgSwitch(Boolean.TRUE.equals(request.getImgSwitch())); vo.setItems(new ArrayList<>(allRows)); vo.setGroups(groups); long finishedAt = System.nanoTime(); @@ -1229,10 +1230,11 @@ public class SimilarAsinTaskService { } String prompt = readAiPrompt(task); String apiKey = readApiKey(task); + boolean imgSwitch = readImgSwitch(task); int batchSize = Math.max(1, properties.getCozeBatchSize()); List result = new ArrayList<>(); for (int i = 0; i < items.size(); i += batchSize) { - result.addAll(cozeClient.inspect(items.subList(i, Math.min(i + batchSize, items.size())), prompt, apiKey)); + result.addAll(cozeClient.inspect(items.subList(i, Math.min(i + batchSize, items.size())), prompt, apiKey, imgSwitch)); if (progressHook != null) { progressHook.run(); } @@ -1543,6 +1545,14 @@ public class SimilarAsinTaskService { } } + private boolean readImgSwitch(FileTaskEntity task) { + try { + return Boolean.TRUE.equals(readParsedPayload(task).getImgSwitch()); + } catch (Exception ignored) { + return false; + } + } + private void finalizeTask(FileTaskEntity task, String error, int rowCount, boolean assembleWorkbook) { String finalError = error; FileResultEntity result = null; @@ -1910,6 +1920,7 @@ public class SimilarAsinTaskService { } String prompt = readAiPrompt(task); String apiKey = readApiKey(task); + boolean imgSwitch = readImgSwitch(task); int batchSize = Math.max(1, properties.getCozeBatchSize()); // P1-1:检测到 720712008 风暴时强制把 batch 降到 1,隔离毒行; // 持续 5+ 次提交命中率 ≥ 40% 才会触发,正常波动不影响吞吐。 @@ -1974,7 +1985,7 @@ public class SimilarAsinTaskService { int batchIndex = 1; for (int i = 0; i < submitLimit; i += batchSize) { List batchCandidates = readyCandidates.subList(i, Math.min(i + batchSize, submitLimit)); - pending |= submitCozeBatch(task, result, job, batchCandidates, batchIndex, batchTotal, prompt, apiKey, allRowsByBaseId); + pending |= submitCozeBatch(task, result, job, batchCandidates, batchIndex, batchTotal, prompt, apiKey, imgSwitch, allRowsByBaseId); batchIndex++; } return pending || countPendingCozeStates(task.getId()) > 0; @@ -2089,6 +2100,7 @@ public class SimilarAsinTaskService { int batchTotal, String prompt, String apiKey, + boolean imgSwitch, Map> allRowsByBaseId) { if (batchCandidates == null || batchCandidates.isEmpty()) { return false; @@ -2115,7 +2127,7 @@ public class SimilarAsinTaskService { SimilarAsinCozeClient.CozeCredentialRef credential = cozeClient.nextCredential(); try { SimilarAsinCozeClient.CozeSubmitResponse submit = submitCozeWorkflowThrottled( - batchRows, prompt, apiKey, credential, true); + batchRows, prompt, apiKey, imgSwitch, credential, true); if (submit.immediateData() != null && !submit.immediateData().isBlank()) { List cozeRows = cozeClient.mergeRowsFromDataText(batchRows, submit.immediateData()); String emptyResultMessage = emptyCozeResultMessage(cozeRows, batchRows.size()); @@ -2426,7 +2438,7 @@ public class SimilarAsinTaskService { } try { SimilarAsinCozeClient.CozeSubmitResponse submit = - submitCozeWorkflowThrottled(batchRows, readAiPrompt(task), readApiKey(task), + submitCozeWorkflowThrottled(batchRows, readAiPrompt(task), readApiKey(task), readImgSwitch(task), cozeClient.credentialByName(context.credentialName()), false); Map> allRowsByBaseId = allRowsByBaseIdForPoll(task); if (submit.immediateData() != null && !submit.immediateData().isBlank()) { @@ -2488,6 +2500,7 @@ public class SimilarAsinTaskService { List rows, String prompt, String apiKey, + boolean imgSwitch, SimilarAsinCozeClient.CozeCredentialRef credential, boolean allowCredentialFallback) throws Exception { int attempts = allowCredentialFallback ? Math.max(1, cozeClient.configuredCredentialCount()) : 1; @@ -2521,7 +2534,7 @@ public class SimilarAsinTaskService { } try (lockHandle; borrowedCredential) { SimilarAsinCozeClient.CozeSubmitResponse response = - cozeClient.submitWorkflow(rows, prompt, apiKey, currentCredential); + cozeClient.submitWorkflow(rows, prompt, apiKey, imgSwitch, currentCredential); // 提交完成立即记录时间戳,用于下次进入循环时计算节流等待。 lastCozeSubmitAtByCredential.put(credentialKey, System.currentTimeMillis()); return response; @@ -2713,7 +2726,7 @@ public class SimilarAsinTaskService { int partIndex = 1; for (List partRows : partitions) { SimilarAsinCozeClient.CozeSubmitResponse submit = - submitCozeWorkflowThrottled(partRows, readAiPrompt(task), readApiKey(task), + submitCozeWorkflowThrottled(partRows, readAiPrompt(task), readApiKey(task), readImgSwitch(task), cozeClient.credentialByName(context.credentialName()), false); if (submit.immediateData() != null && !submit.immediateData().isBlank()) { List cozeRows = @@ -2847,7 +2860,7 @@ public class SimilarAsinTaskService { try { taskFileJobService.touchRunning(context.jobId()); SimilarAsinCozeClient.CozeSubmitResponse submit = - submitCozeWorkflowThrottled(batchRows, readAiPrompt(task), readApiKey(task), + submitCozeWorkflowThrottled(batchRows, readAiPrompt(task), readApiKey(task), readImgSwitch(task), cozeClient.credentialByName(context.credentialName()), false); Map> allRowsByBaseId = allRowsByBaseIdForPoll(task); if (submit.immediateData() != null && !submit.immediateData().isBlank()) { @@ -3691,13 +3704,26 @@ public class SimilarAsinTaskService { if (taskId == null || taskId <= 0) { return false; } - Long count = taskScopeStateMapper.selectCount(new LambdaQueryWrapper() + List states = taskScopeStateMapper.selectList(new LambdaQueryWrapper() .eq(TaskScopeStateEntity::getTaskId, taskId) .eq(TaskScopeStateEntity::getModuleType, MODULE_TYPE) .isNull(TaskScopeStateEntity::getCozeStatus) - .isNotNull(TaskScopeStateEntity::getLastChunkAt) - .eq(TaskScopeStateEntity::getCompleted, 1)); - return count != null && count > 0; + .isNotNull(TaskScopeStateEntity::getLastChunkAt)); + if (states == null || states.isEmpty()) { + return false; + } + boolean hasCompletedScope = false; + for (TaskScopeStateEntity state : states) { + if (state == null) { + continue; + } + if (Integer.valueOf(1).equals(state.getCompleted())) { + hasCompletedScope = true; + continue; + } + return false; + } + return hasCompletedScope; } private boolean isJavaSideProcessing(Long taskId) { @@ -3737,6 +3763,9 @@ public class SimilarAsinTaskService { SimilarAsinResultRowDto row) { } + private record PythonUploadProgress(int current, int total, String unit) { + } + private String buildTaskOwnerScopeKey(FileTaskEntity task) { Long taskId = task == null ? null : task.getId(); return "task:" + taskId + ":owner:" + firstNonBlank(ownerFromTask(task), currentInstanceId()); @@ -4812,8 +4841,8 @@ public class SimilarAsinTaskService { vo.setSourceFilename(row.getSourceFilename()); vo.setResultFilename(row.getResultFilename()); vo.setDownloadUrl(buildFreshDownloadUrl(row)); - attachFileJobState(vo, row, job); vo.setTaskStatus(task == null ? null : task.getStatus()); + attachFileJobState(vo, row, job, task); vo.setSuccess(row.getSuccess() != null && row.getSuccess() == 1); vo.setError(row.getErrorMessage()); vo.setRowCount(row.getRowCount()); @@ -4838,20 +4867,20 @@ public class SimilarAsinTaskService { } } - private void attachFileJobState(SimilarAsinHistoryItemVo vo, FileResultEntity row, TaskFileJobEntity job) { + private void attachFileJobState(SimilarAsinHistoryItemVo vo, FileResultEntity row, TaskFileJobEntity job, FileTaskEntity task) { vo.setFileReady(row.getResultFileUrl() != null && !row.getResultFileUrl().isBlank()); if (job == null) { vo.setFileStatus(Boolean.TRUE.equals(vo.getFileReady()) ? "SUCCESS" : null); - attachFileProgress(vo, row, job); + attachFileProgress(vo, row, job, task); return; } vo.setFileJobId(job.getId()); vo.setFileStatus(job.getStatus()); vo.setFileError(job.getErrorMessage()); - attachFileProgress(vo, row, job); + attachFileProgress(vo, row, job, task); } - private void attachFileProgress(SimilarAsinHistoryItemVo vo, FileResultEntity row, TaskFileJobEntity job) { + private void attachFileProgress(SimilarAsinHistoryItemVo vo, FileResultEntity row, TaskFileJobEntity job, FileTaskEntity task) { if (row == null || row.getTaskId() == null) { return; } @@ -4866,22 +4895,22 @@ public class SimilarAsinTaskService { int cozeCompleted = countCompletedCozeStates(taskId); int cozePending = countPendingCozeStates(taskId); boolean uploadComplete = isResultSubmissionComplete(taskId); + if (!uploadComplete) { + if (task != null && !STATUS_RUNNING.equals(task.getStatus())) { + return; + } + attachPythonUploadProgress(vo, taskId); + return; + } TaskProgressSnapshotEntity snapshot = taskProgressSnapshotService.find(taskId, MODULE_TYPE); if (cozeCompleted + cozePending > 0) { int total = calculateCozeDisplayTotal(snapshot, cozeCompleted + cozePending); - if (!uploadComplete) { - total = Math.max(total, cozeCompleted + cozePending + 1); - } int current = Math.max(0, Math.min(cozeCompleted, total)); vo.setFileProgressCurrent(current); vo.setFileProgressTotal(total); int percent = calculateDisplayProgressPercent(current, total, job, snapshot == null ? null : snapshot.getUpdatedAt()); percent = Math.max(percent, calculateSnapshotDisplayPercent(snapshot, job)); - vo.setFileProgressPercent(Math.min(uploadComplete ? 99 : 98, percent)); - if (!uploadComplete) { - vo.setFileProgressMessage(buildUploadingCozeProgressMessage(current, total, cozePending)); - return; - } + vo.setFileProgressPercent(Math.min(99, percent)); vo.setFileProgressMessage(cozePending > 0 ? buildCozeProgressMessage(current, total, cozePending) : "Coze 已回流 " + current + "/" + total + " 批次,正在生成结果文件"); @@ -4905,6 +4934,121 @@ public class SimilarAsinTaskService { vo.setFileProgressMessage(snapshot.getMessage()); } + private void attachPythonUploadProgress(SimilarAsinHistoryItemVo vo, Long taskId) { + PythonUploadProgress progress = resolvePythonUploadProgress(taskId); + int total = progress.total() > 0 ? progress.total() : Math.max(1, progress.current() + 1); + int current = Math.max(0, Math.min(progress.current(), total)); + int percent = current <= 0 ? 1 : Math.min(95, (int) Math.floor(current * 100.0 / total)); + vo.setFileProgressCurrent(current); + vo.setFileProgressTotal(total); + vo.setFileProgressPercent(percent); + vo.setFileProgressMessage(buildPythonUploadProgressMessage(current, total, progress.unit())); + } + + private PythonUploadProgress resolvePythonUploadProgress(Long taskId) { + PythonUploadProgress chunkProgress = resolvePythonChunkProgress(taskId); + if (chunkProgress.total() > 0) { + return chunkProgress; + } + if (chunkProgress.current() > 0) { + return new PythonUploadProgress(chunkProgress.current(), chunkProgress.current() + 1, chunkProgress.unit()); + } + int totalRows = 0; + try { + FileTaskEntity task = fileTaskMapper.selectById(taskId); + totalRows = allRowCount(task); + } catch (Exception ignored) { + totalRows = 0; + } + int uploadedRows = countSubmittedRows(taskId); + if (totalRows <= 0 && uploadedRows > 0) { + totalRows = uploadedRows + 1; + } + return new PythonUploadProgress(uploadedRows, totalRows, "行"); + } + + private PythonUploadProgress resolvePythonChunkProgress(Long taskId) { + if (taskId == null || taskId <= 0) { + return new PythonUploadProgress(0, 0, "分片"); + } + List states = taskScopeStateMapper.selectList(new LambdaQueryWrapper() + .eq(TaskScopeStateEntity::getTaskId, taskId) + .eq(TaskScopeStateEntity::getModuleType, MODULE_TYPE) + .isNull(TaskScopeStateEntity::getCozeStatus) + .orderByDesc(TaskScopeStateEntity::getUpdatedAt)); + if (states == null || states.isEmpty()) { + return resolvePythonChunkProgressFromChunks(taskId); + } + int current = 0; + int total = 0; + for (TaskScopeStateEntity state : states) { + if (state == null) { + continue; + } + int stateTotal = state.getChunkTotal() == null ? 0 : state.getChunkTotal(); + int stateCurrent = state.getReceivedChunkCount() == null ? 0 : state.getReceivedChunkCount(); + if (stateTotal > total || total <= 0 && stateCurrent > current) { + total = stateTotal; + current = stateCurrent; + } + } + return new PythonUploadProgress(current, total, "分片"); + } + + private PythonUploadProgress resolvePythonChunkProgressFromChunks(Long taskId) { + List chunks = taskChunkMapper.selectList(new LambdaQueryWrapper() + .eq(TaskChunkEntity::getTaskId, taskId) + .eq(TaskChunkEntity::getModuleType, MODULE_TYPE)); + if (chunks == null || chunks.isEmpty()) { + return new PythonUploadProgress(0, 0, "分片"); + } + Map receivedByScope = new LinkedHashMap<>(); + Map totalByScope = new LinkedHashMap<>(); + for (TaskChunkEntity chunk : chunks) { + if (chunk == null) { + continue; + } + String scopeHash = firstNonBlank(chunk.getScopeHash(), ""); + receivedByScope.merge(scopeHash, 1, Integer::sum); + if (chunk.getChunkTotal() != null && chunk.getChunkTotal() > 0) { + totalByScope.merge(scopeHash, chunk.getChunkTotal(), Math::max); + } + } + int current = 0; + int total = 0; + for (Map.Entry entry : receivedByScope.entrySet()) { + int scopeCurrent = entry.getValue() == null ? 0 : entry.getValue(); + int scopeTotal = totalByScope.getOrDefault(entry.getKey(), 0); + if (scopeTotal > total || total <= 0 && scopeCurrent > current) { + current = scopeCurrent; + total = scopeTotal; + } + } + return new PythonUploadProgress(current, total, "分片"); + } + + private int countSubmittedRows(Long taskId) { + if (taskId == null || taskId <= 0) { + return 0; + } + int total = 0; + List chunks = taskChunkMapper.selectList(new LambdaQueryWrapper() + .eq(TaskChunkEntity::getTaskId, taskId) + .eq(TaskChunkEntity::getModuleType, MODULE_TYPE)); + if (chunks == null || chunks.isEmpty()) { + return 0; + } + for (TaskChunkEntity chunk : chunks) { + total += readChunkRows(chunk).size(); + } + return total; + } + + private String buildPythonUploadProgressMessage(int current, int total, String unit) { + String safeUnit = unit == null || unit.isBlank() ? "分片" : unit; + return "等待 Python 回传,已回传 " + Math.max(0, current) + "/" + Math.max(1, total) + " " + safeUnit; + } + private int calculateCozeDisplayTotal(TaskProgressSnapshotEntity snapshot, int observedCozeStates) { int observed = Math.max(0, observedCozeStates); // 小任务 totalCount <= 3 时直接使用 observed,避免 totalCount - 3 → 0 引起进度条 0/0。 @@ -4924,15 +5068,6 @@ public class SimilarAsinTaskService { } return "Coze 已回流 " + safeCompleted + "/" + safeTotal + " 批次,等待结果文件"; } - private String buildUploadingCozeProgressMessage(int completed, int total, int pending) { - int safeTotal = Math.max(1, total); - int safeCompleted = Math.max(0, Math.min(completed, safeTotal)); - int submitted = Math.max(safeCompleted, Math.min(safeTotal, safeCompleted + Math.max(0, pending))); - if (pending > 0) { - return "Python 仍在回传,Coze 已提交 " + submitted + "/" + safeTotal + " 批次"; - } - return "Python 仍在回传,Coze 已回流 " + safeCompleted + "/" + safeTotal + " 批次"; - } private String fmt(LocalDateTime t) { return t == null ? null : t.toString(); @@ -4968,10 +5103,11 @@ public class SimilarAsinTaskService { return val == null ? "" : val.replace(String.valueOf((char) 0xFEFF), "").replace((char) 0x3000, ' ').trim().replaceAll("\\s+", " "); } - private String buildParsedPayloadJson(String aiPrompt, String apiKey, List sourceFiles, List headers, List groups, List allRows) { + private String buildParsedPayloadJson(String aiPrompt, String apiKey, Boolean imgSwitch, List sourceFiles, List headers, List groups, List allRows) { SimilarAsinParsedPayloadDto payload = new SimilarAsinParsedPayloadDto(); payload.setAiPrompt(normalize(aiPrompt)); payload.setApiKey(normalize(apiKey)); + payload.setImgSwitch(Boolean.TRUE.equals(imgSwitch)); payload.setSourceFiles(sourceFiles == null ? List.of() : sourceFiles); payload.setHeaders(headers == null ? List.of() : headers); payload.setItems(allRows == null ? List.of() : new ArrayList<>(allRows)); @@ -4980,10 +5116,11 @@ public class SimilarAsinTaskService { return writeJson(payload, "保存解析结果失败"); } - private String buildTaskResultJson(String aiPrompt, String apiKey, List sourceFiles, String parsedPayloadPointer) { + private String buildTaskResultJson(String aiPrompt, String apiKey, Boolean imgSwitch, List sourceFiles, String parsedPayloadPointer) { Map payload = new LinkedHashMap<>(); payload.put("aiPrompt", normalize(aiPrompt)); payload.put("apiKey", normalize(apiKey)); + payload.put("imgSwitch", Boolean.TRUE.equals(imgSwitch)); payload.put("sourceFileKeys", sourceFiles == null ? List.of() : sourceFiles.stream() .map(SimilarAsinSourceFileDto::getFileKey) .filter(Objects::nonNull) diff --git a/backend-java/src/main/resources/db/V51__coze_credential_pool.sql b/backend-java/src/main/resources/db/V51__coze_credential_pool.sql index c792e5b..0966bce 100644 --- a/backend-java/src/main/resources/db/V51__coze_credential_pool.sql +++ b/backend-java/src/main/resources/db/V51__coze_credential_pool.sql @@ -17,7 +17,7 @@ CREATE TABLE IF NOT EXISTS biz_coze_credential ( INSERT INTO biz_coze_credential (module_type, credential_name, workflow_id, token, enabled, max_concurrent, sort_order) VALUES ('APPEARANCE_PATENT', 'appearance-1', '7639685157562089513', 'Bearer sat_CztofPRhIKFKeaPZBIRxocfckqhsdCZZ45NPhkf7WOZjbX36vnVSfVV30T6u2rSX', 1, 0, 10), -('APPEARANCE_PATENT', 'appearance-2', '7639688221823778850', 'Bearer sat_2VsTpfWXYG3EkCo8OQfLwJEWqhduCL4NEw7sSCsABppkW61kkSRPIac9coNlEnHE', 1, 0, 20), +('APPEARANCE_PATENT', 'appearance-2', '7644952624353329202', 'Bearer sat_2VsTpfWXYG3EkCo8OQfLwJEWqhduCL4NEw7sSCsABppkW61kkSRPIac9coNlEnHE', 1, 0, 20), ('SIMILAR_ASIN', 'similar-1', '7639708860686024756', 'Bearer sat_vqmb97BiXbMW3XVyG9htWQKjZ2F55CaW2FRrT9bDdPha7a3hxmXnMNCE1XNHdCVU', 1, 0, 10), ('SIMILAR_ASIN', 'similar-2', '7635328462404583478', 'Bearer sat_gsInckdsN0qqhnZSK7K4Zevw6neJCHmYHyIbm85oGgJIGEmSdkH5OFctSKLsAHvT', 1, 0, 20) ON DUPLICATE KEY UPDATE diff --git a/backend-java/src/main/resources/db/V57__update_appearance_patent_workflow.sql b/backend-java/src/main/resources/db/V57__update_appearance_patent_workflow.sql new file mode 100644 index 0000000..09229cc --- /dev/null +++ b/backend-java/src/main/resources/db/V57__update_appearance_patent_workflow.sql @@ -0,0 +1,4 @@ +UPDATE biz_coze_credential + SET workflow_id = '7644952624353329202' + WHERE module_type = 'APPEARANCE_PATENT' + AND credential_name = 'appearance-2'; diff --git a/frontend-vue/src/pages/brand/components/BrandCollectDataTab.vue b/frontend-vue/src/pages/brand/components/BrandCollectDataTab.vue index 059945f..3d3ec6b 100644 --- a/frontend-vue/src/pages/brand/components/BrandCollectDataTab.vue +++ b/frontend-vue/src/pages/brand/components/BrandCollectDataTab.vue @@ -25,28 +25,32 @@
筛选条件
- - -
-
- - + +
+ + + +
+
- 国家与顺序 + 采集国家 保存中…

- 勾选需要采集的国家(暂定 5 国,至少保留 1 个);上方勾选区先按已选顺序排列,其余未选国家排在后面。拖拽下方列表可调整顺序。 + 每次任务只采集一个国家,选择后会自动保存,下次进入默认使用该国家。

-
-
+
+
检测条件
+ +
+