Files
crawler-plugin/app/assets/similar-asin.js
2026-06-08 09:19:15 +08:00

2 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import{d as je,o as qe,q as Oe,a as u,c as i,b as Ke,e as a,F as se,r as te,t as r,w as Ve,v as Ye,f as h,u as _e,n as Qe,g as p,h as j,i as q,E as v,_ as We,j as Xe,k as Ze}from"./pywebview-B8lwamDf.js";import{B as es,H as ss,I as ts,v as ye,J as as,K as ls,L as ns,s as rs,M as os,N as us,F as is,O as cs}from"./java-modules-B9jblDzU.js";import{e as ds}from"./brand-DE-sObfq.js";import{c as fs}from"./categorized-timers-JPA-olTr.js";const vs={class:"page-shell module-page"},gs={class:"main-content"},ps={class:"left-panel"},hs={class:"upload-zone"},ks={class:"selected-files"},_s={key:0},ys={class:"condition-card"},Is={class:"switch-row"},ws={class:"run-row"},Ss=["disabled"],Ps=["disabled"],Cs={key:0,class:"parse-card"},bs={key:1,class:"queue-payload"},ms={class:"right-panel"},Ns={class:"task-list-wrap"},Fs={class:"clean-result-summary"},Ts={class:"summary-card"},Es={class:"summary-card"},Rs={class:"summary-card"},As={class:"summary-card"},Ds={class:"result-list-wrap"},Us={key:0,class:"empty-tasks"},xs={key:1,class:"task-list clean-result-list"},$s={class:"left"},Ms={class:"id"},Gs={class:"files"},zs={class:"files"},Ls={class:"files"},Bs={class:"files"},Hs={key:0,class:"files result-hint"},Js={key:1,class:"file-progress"},js={class:"file-progress-meta"},qs={class:"file-progress-track"},Os={key:0,class:"file-progress-count"},Ks={class:"task-right"},Vs={class:"status running"},Ys=["onClick"],Qs={class:"result-list-wrap"},Ws={key:0,class:"empty-tasks"},Xs={key:1,class:"task-list clean-result-list"},Zs={class:"left"},et={class:"id"},st={class:"files"},tt={class:"files"},at={class:"files"},lt={key:0,class:"files"},nt={key:1,class:"files result-hint"},rt={key:2,class:"file-progress"},ot={class:"file-progress-meta"},ut={class:"file-progress-track"},it={key:0,class:"file-progress-count"},ct={key:3,class:"files"},dt={class:"task-right"},ft=["onClick"],vt=["onClick"],gt=3e3,pt=je({__name:"BrandSimilarAsinTab",setup(kt){const D=p([]),m=p([]),I=p(null),w=p(null),U=p(!1),x=p(!1),O=p(!1),S=p(""),d=p([]),c=p([]),k=p(null),K=p(!1);let N=null,ae=0,F=!1;const T=fs("similar-asin"),E=p({pendingTaskCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),f=p([]),_=p({}),R=j(()=>I.value||w.value),V=j(()=>{const e=I.value;return!e?.taskId||f.value.some(t=>t.taskId===e.taskId)?null:{taskId:e.taskId,sourceFilename:e.sourceFilename,rowCount:e.acceptedRows,taskStatus:"PENDING",success:!1}}),le=j(()=>{const e=new Set([...d.value,...c.value]),s=f.value.filter(l=>{const n=y(l);return l.taskId!=null&&(e.has(l.taskId)||n==="RUNNING"||n==="PENDING")}).map(l=>re(l));for(const[l,n]of Object.entries(_.value)){const o=Number(l);!Number.isFinite(o)||o<=0||!e.has(o)&&y(n)!=="RUNNING"&&y(n)!=="PENDING"||s.some(g=>g.taskId===o)||s.push(re(n))}return V.value?s.some(l=>l.taskId===V.value?.taskId)?s:[V.value,...s]:s}),ne=j(()=>f.value.filter(e=>{const s=y(e);return s!=="RUNNING"&&s!=="PENDING"}));function re(e){if(e.taskId==null)return e;const s=_.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 $(){return is("similar-asin").trim()}function M(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"),o=String(s.getHours()).padStart(2,"0"),g=String(s.getMinutes()).padStart(2,"0"),J=String(s.getSeconds()).padStart(2,"0");return`${t}-${l}-${n} ${o}:${g}:${J}`}function Ie(e){return e?e.length<=10?"***":`${e.slice(0,6)}***${e.slice(-4)}`:""}function we(e){return{...e,data:e.data?{...e.data,api_key:Ie(String(e.data.api_key||""))}:e.data}}function oe(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function Se(){return Number(oe())||0}function Y(){return`similar-asin:tasks:${oe()}`}function Pe(e){return{taskId:e.taskId,totalRows:e.totalRows,acceptedRows:e.acceptedRows,groupCount:e.groupCount,droppedRows:e.droppedRows}}function P(){if(typeof window>"u")return;const e=Array.from(new Set([...d.value,...c.value]));e.length?window.localStorage.setItem(Y(),JSON.stringify(e)):window.localStorage.removeItem(Y())}function Ce(){if(!(typeof window>"u"))try{const e=window.localStorage.getItem(Y()),s=e?JSON.parse(e):[];d.value=Array.isArray(s)?s.filter(t=>typeof t=="number"&&t>0):[]}catch{d.value=[]}}async function ue(e){const s=q();if(!s?.upload_file_to_java)throw new Error("当前桌面端未提供文件上传能力");const t=[];for(const l of e){const n=typeof l=="string"?l:l.absolutePath,o=typeof l=="string"?void 0:l.relativePath,g=await s.upload_file_to_java(n,o);if(!g?.success||!g.data)throw new Error(g?.error||g?.message||`上传失败:${n}`);t.push(g.data)}return t}async function be(){const e=q();if(!e?.select_brand_xlsx_files||!e.upload_file_to_java){v.warning("当前桌面端未提供文件选择或上传能力");return}const s=await e.select_brand_xlsx_files();if(!s?.length)return;const t=await ue(s);m.value=t,D.value=t.map(l=>l.relativePath||l.originalFilename||l.fileKey),I.value=null,w.value=null,S.value=""}async function me(){const e=q();if(!e?.select_brand_folder||!e.upload_file_to_java){v.warning("当前桌面端未提供文件夹选择或上传能力");return}try{const s=await e.select_brand_folder();if(!s)return;const t=await ds(s);if(!t.success||!t.items?.length){v.warning(t.error||"该文件夹下没有可用的 xlsx 文件");return}const l=await ue(t.items);m.value=l,D.value=t.items.map(n=>n.relativePath||n.absolutePath),I.value=null,w.value=null,S.value="",v.success(`已选择文件夹内 ${t.items.length} 个 Excel 文件`)}catch(s){v.error(s instanceof Error?s.message:"选择失败")}}async function Ne(){if(!m.value.length){v.warning("请先选择 Excel");return}if(!$()){v.warning("请先在左上角设置中填写货源查询密钥");return}U.value=!0;try{const e=m.value.map(t=>({fileKey:t.fileKey,originalFilename:t.originalFilename,relativePath:t.relativePath})),s=await ss(e,$(),O.value);I.value=s,w.value=null,S.value="",v.success(`解析完成,共 ${s.acceptedRows}`)}catch(e){v.error(e instanceof Error?e.message:"解析失败")}finally{U.value=!1}}async function Fe(){const e=q(),s=I.value,t=s?.taskId;if(!t){v.warning("请先解析文件");return}if(!e?.enqueue_json){v.error("当前环境未启用 pywebview enqueue_json");return}if(!$()){v.warning("请先在左上角设置中填写货源查询密钥");return}x.value=!0;try{const l={type:"similar-asin-run",ts:Date.now(),data:{taskId:t,user_id:Se(),api_key:$(),sourceFileCount:s.sourceFileCount||0,totalRows:s.totalRows||0,acceptedRows:s.acceptedRows||0,groupCount:s.groupCount||0}};S.value=JSON.stringify(we(l),null,2),await ts(t);const n=await e.enqueue_json(l);if(!n?.success){v.error(n?.error||"推送失败");return}w.value=Pe(s),Te(t),ie(),await z(),await L({force:!0}),v.success("已推送到 Python 队列")}finally{x.value=!1}}function ie(){I.value=null,S.value=""}function Te(e){d.value.includes(e)||(d.value=[...d.value,e],P()),C()}function Q(e){if(d.value=d.value.filter(s=>s!==e),!c.value.includes(e)){const s={..._.value};delete s[e],_.value=s}P()}function Ee(e){c.value.includes(e)||(c.value=[...c.value,e],P()),C()}function G(e){if(c.value=c.value.filter(s=>s!==e),!d.value.includes(e)){const s={..._.value};delete s[e],_.value=s}P()}function Re(e){if(e&&(Q(e),G(e),I.value?.taskId===e&&ie(),w.value?.taskId===e&&(w.value=null),f.value=f.value.filter(s=>s.taskId!==e),_.value[e])){const s={..._.value};delete s[e],_.value=s}}function C(){F||k.value==null&&Ae(!0)}function ce(){k.value!=null&&(T.clearTimer("task-poll",k.value),k.value=null)}function Ae(e=!1){if(F)return;if(k.value!=null){if(!e)return;T.clearTimer("task-poll",k.value),k.value=null}const s=async()=>{k.value=null,!F&&(!d.value.length&&!c.value.length||(await De(),!F&&k.value==null&&(d.value.length||c.value.length)&&(k.value=T.setTimeout("task-poll",s,ye()))))};e?s():k.value=T.setTimeout("task-poll",s,ye())}async function De(){if(K.value||!d.value.length&&!c.value.length){!d.value.length&&!c.value.length&&ce();return}K.value=!0;try{let e=!1,s=!1;const t=Array.from(new Set([...d.value,...c.value]));if(t.length){const l=await cs(t,{force:c.value.length>0});for(const n of l.items||[]){const o=n.task;if(!o?.id)continue;const g=n.items?.[0];if(g&&(_.value={..._.value,[o.id]:g},Ue(g)),(o.status==="SUCCESS"||o.status==="FAILED")&&(Q(o.id),e=!0,o.status==="SUCCESS"?Ee(o.id):G(o.id)),g&&o.status==="SUCCESS"&&c.value.includes(o.id)){const J=(g.fileStatus||"").toUpperCase();(g.fileReady||J==="SUCCESS"||J==="FAILED")&&(G(o.id),e=!0,s=!0)}}l.missingTaskIds?.length&&(l.missingTaskIds.forEach(n=>{Q(n),G(n)}),s=!0,e=!0)}e&&await z(),s&&await L(),xe()}finally{K.value=!1}}function Ue(e){if(!e.taskId&&!e.resultId)return;const s=f.value.findIndex(t=>e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId);s>=0?f.value[s]={...f.value[s],...e}:f.value=[e,...f.value]}function xe(){if(!c.value.length)return;const e=[];for(const s of c.value){const t=f.value.find(o=>o.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)}c.value=e,P(),c.value.length&&C()}function $e(){const e=f.value.filter(s=>s.taskId!=null&&b(s)).map(s=>s.taskId);c.value=Array.from(new Set(e)),P(),c.value.length&&C()}function Me(){const e=f.value.filter(s=>s.taskId!=null&&y(s)==="RUNNING").map(s=>s.taskId);e.length&&(d.value=Array.from(new Set([...d.value,...e])),P(),C())}async function z(){E.value=await as()}async function L(e={}){const s=Date.now();if(!(!e.force&&f.value.length&&s-ae<gt))return N||(N=ls().then(t=>{f.value=Ge(f.value,t.items||[]),ae=Date.now()}).finally(()=>{N=null}),N)}function Ge(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 o=n.resultId!=null?l.get(n.resultId):n.taskId!=null?t.get(n.taskId):void 0;return ze(o,n)})}function ze(e,s){return!e||!((y(e)==="RUNNING"||b(e)||A(e))&&!A(s)&&!Z(s))?s:{...s,fileJobId:s.fileJobId??e.fileJobId,fileStatus:s.fileStatus||e.fileStatus,fileError:s.fileError||e.fileError,fileReady:s.fileReady||e.fileReady,fileProgressPercent:W(s.fileProgressPercent)?s.fileProgressPercent:e.fileProgressPercent,fileProgressCurrent:W(s.fileProgressCurrent)?s.fileProgressCurrent:e.fileProgressCurrent,fileProgressTotal:W(s.fileProgressTotal)?s.fileProgressTotal:e.fileProgressTotal,fileProgressMessage:(s.fileProgressMessage||"").trim()?s.fileProgressMessage:e.fileProgressMessage}}function W(e){const s=Number(e);return Number.isFinite(s)&&s>0}function de(e){const s=y(e);return s==="RUNNING"?"执行中":s==="PENDING"?"已解析待推送":b(e)?"结果生成中":X(e)?"结果生成失败":s==="SUCCESS"||e.success?"已完成":s==="FAILED"?"失败":"等待中"}function Le(e){const s=y(e);return s==="RUNNING"||b(e)?"running":X(e)||s==="FAILED"?"failed":s==="SUCCESS"||e.success?"success":"pending"}function b(e){const s=y(e),t=(e.fileStatus||"").toUpperCase();return!(s!=="SUCCESS"||Z(e)||t==="FAILED"||t==="SUCCESS")}function y(e){return(e.taskStatus||"").toUpperCase()}function X(e){return(e.fileStatus||"").toUpperCase()==="FAILED"}function B(e){if(X(e))return e.fileError||"结果文件生成失败,请稍后重试或检查后端日志";if(A(e)||!b(e))return"";const s=(e.fileStatus||"").toUpperCase();return s==="RUNNING"?"任务已完成,正在等待 Coze 回流并组装结果文件,下载按钮稍后出现":s==="PENDING"?"任务已完成,结果文件已入队,正在等待后端开始处理":"任务已完成,正在生成结果文件,下载按钮稍后出现"}function Z(e){return!!(e.resultId&&(e.fileReady||e.downloadUrl))}function H(e){const s=Number(e.fileProgressPercent||0);return Number.isFinite(s)&&s>0?Math.max(0,Math.min(100,Math.round(s))):he(e)?pe(e)==="PENDING"?6:10:0}function fe(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 ve(e){const s=(e.fileProgressMessage||"").trim(),t=Be(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 Be(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 A(e){return(y(e)==="RUNNING"||b(e))&&(ge(e)||he(e))}function ge(e){return ee(e)||Number(e.fileProgressPercent||0)>0||!!(e.fileProgressMessage||"").trim()}function ee(e){return(e.fileProgressTotal||0)>0}function pe(e){return(e.fileStatus||"").toUpperCase()}function He(e){const s=pe(e);return e.fileJobId!=null||s==="PENDING"||s==="RUNNING"}function he(e){return He(e)&&!ge(e)}async function Je(e){if(!e.resultId)return;const s=e.downloadUrl||ns(e.resultId),t=e.resultFilename||`${e.sourceFilename||"similar-asin"}.xlsx`,l=await rs(s,t,`similar-asin:${e.resultId}`);l.success?v.success(`已保存: ${l.path||t}`):l.error&&l.error!=="用户取消"&&v.error(l.error)}async function ke(e){try{const s=y(e),t=e.taskId;t!=null&&(s==="RUNNING"||s==="PENDING"||!e.resultId)?(await os(t),Re(t)):e.resultId&&(await us(e.resultId),e.taskId&&(f.value=f.value.filter(n=>n.taskId!==e.taskId))),await z(),await L({force:!0}),v.success("已删除")}catch(s){v.error(s instanceof Error?s.message:"删除失败")}}return qe(async()=>{Ce(),await Promise.all([z().catch(()=>{}),L().catch(()=>{})]),$e(),Me(),(d.value.length||c.value.length)&&C()}),Oe(()=>{F=!0,ce(),T.clearScope()}),(e,s)=>(u(),i("div",vs,[Ke(es,{active:"similar-asin"}),a("div",gs,[a("aside",ps,[s[5]||(s[5]=a("div",{class:"section-title"},"上传文件",-1)),a("div",hs,[s[1]||(s[1]=a("div",{class:"hint"},"选择 Excel 后点击解析,后端会提取 id、ASIN、国家、价格每一行都会独立送检。",-1)),a("div",{class:"btns"},[a("button",{type:"button",class:"opt-btn",onClick:be},"选择 Excel"),a("button",{type:"button",class:"opt-btn",onClick:me},"选择文件夹")]),a("div",ks,[D.value.length?(u(!0),i(se,{key:1},te(D.value,t=>(u(),i("span",{key:t},r(t),1))),128)):(u(),i("span",_s,"暂未选择文件"))])]),a("div",ys,[s[4]||(s[4]=a("div",{class:"section-title"},"检测条件",-1)),a("label",Is,[s[2]||(s[2]=a("span",null,[a("strong",null,"图片检测"),a("em",null,"开启后请求 Coze 时携带 img_switch=true")],-1)),Ve(a("input",{"onUpdate:modelValue":s[0]||(s[0]=t=>O.value=t),type:"checkbox"},null,512),[[Ye,O.value]]),s[3]||(s[3]=a("i",null,null,-1))])]),a("div",ws,[a("button",{type:"button",class:"btn-run",disabled:U.value||!m.value.length,onClick:Ne},r(U.value?"解析中...":"解析并创建任务"),9,Ss),a("button",{type:"button",class:"btn-run btn-queue",disabled:x.value||!I.value?.taskId,onClick:Fe},r(x.value?"推送中...":"推送到 Python 队列"),9,Ps)]),s[6]||(s[6]=a("p",{class:"loading-msg"},"Python 回传字段按 id、asin、国家、价格、标题、图片链接数组提交后端接收分片后按 10 条一批送检,结果区展示真实 Coze 批次进度。",-1)),R.value?(u(),i("div",Cs,[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),S.value?(u(),i("pre",bs,r(S.value),1)):h("",!0)]),a("section",ms,[s[14]||(s[14]=a("div",{class:"panel-header"},"货源查询",-1)),a("div",Ns,[a("div",Fs,[a("div",Ts,[s[7]||(s[7]=a("span",{class:"summary-label"},"运行中任务",-1)),a("strong",null,r(E.value.pendingTaskCount),1)]),a("div",Es,[s[8]||(s[8]=a("span",{class:"summary-label"},"已结束任务",-1)),a("strong",null,r(E.value.processedTaskCount),1)]),a("div",Rs,[s[9]||(s[9]=a("span",{class:"summary-label"},"成功任务",-1)),a("strong",null,r(E.value.successTaskCount),1)]),a("div",As,[s[10]||(s[10]=a("span",{class:"summary-label"},"失败任务",-1)),a("strong",null,r(E.value.failedTaskCount),1)])]),s[13]||(s[13]=a("div",{class:"subsection-title"},"匹配任务",-1)),a("div",Ds,[s[11]||(s[11]=a("div",{class:"result-list-header"},[a("span",null,"当前任务")],-1)),le.value.length?(u(),i("ul",xs,[(u(!0),i(se,null,te(le.value,t=>(u(),i("li",{key:`cur-${t.taskId}`,class:"task-item"},[a("div",$s,[a("span",Ms,r(t.sourceFilename||"货源查询"),1),a("div",Gs,"任务 ID"+r(t.taskId),1),a("div",zs,"开始时间:"+r(M(t.startedAt||t.createdAt)),1),a("div",Ls,"结束时间:"+r(M(t.finishedAt)),1),a("div",Bs,"行数:"+r(t.rowCount??"-"),1),B(t)?(u(),i("div",Hs,r(B(t)),1)):h("",!0),A(t)?(u(),i("div",Js,[a("div",js,[a("span",null,r(fe(t,"处理中")),1),a("span",null,"总进度 "+r(H(t))+"%",1)]),a("div",qs,[a("div",{class:"file-progress-bar",style:_e({width:`${H(t)}%`})},null,4)]),ee(t)?(u(),i("div",Os,r(ve(t)),1)):h("",!0)])):h("",!0)]),a("div",Ks,[a("span",Vs,r(de(t)),1),a("button",{type:"button",class:"btn-delete",onClick:l=>ke(t)},"删除",8,Ys)])]))),128))])):(u(),i("div",Us,"暂无当前任务"))]),a("div",Qs,[s[12]||(s[12]=a("div",{class:"result-list-header"},[a("span",null,"历史记录")],-1)),ne.value.length?(u(),i("ul",Xs,[(u(!0),i(se,null,te(ne.value,t=>(u(),i("li",{key:`his-${t.resultId}-${t.taskId}`,class:"task-item"},[a("div",Zs,[a("span",et,r(t.sourceFilename||"货源查询"),1),a("div",st,"任务 ID"+r(t.taskId??"-"),1),a("div",tt,"开始时间:"+r(M(t.startedAt||t.createdAt)),1),a("div",at,"结束时间:"+r(M(t.finishedAt)),1),t.resultFilename?(u(),i("div",lt,r(t.resultFilename||"下载结果"),1)):h("",!0),B(t)?(u(),i("div",nt,r(B(t)),1)):h("",!0),A(t)?(u(),i("div",rt,[a("div",ot,[a("span",null,r(fe(t,"结果生成中")),1),a("span",null,"总进度 "+r(H(t))+"%",1)]),a("div",ut,[a("div",{class:"file-progress-bar",style:_e({width:`${H(t)}%`})},null,4)]),ee(t)?(u(),i("div",it,r(ve(t)),1)):h("",!0)])):h("",!0),t.error?(u(),i("div",ct,"错误:"+r(t.error),1)):h("",!0)]),a("div",dt,[a("span",{class:Qe(["status",Le(t)])},r(de(t)),3),Z(t)?(u(),i("button",{key:0,type:"button",class:"download",onClick:l=>Je(t)},"下载",8,ft)):h("",!0),t.resultId?(u(),i("button",{key:1,type:"button",class:"btn-delete",onClick:l=>ke(t)},"删除",8,vt)):h("",!0)])]))),128))])):(u(),i("div",Ws,"暂无历史记录"))])])])])]))}}),ht=We(pt,[["__scopeId","data-v-b77550eb"]]);Xe(ht).use(Ze).mount("#app");