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

2 lines
16 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{g as m,N as fe,O as oe,d as ve,o as pe,a as f,c as v,b as me,e as t,F as V,r as Y,t as l,f as B,w as z,p as ae,v as W,n as ne,P as ye,h as le,E as y,i as Q,_ as he,j as ke,k as ge}from"./pywebview-B8lwamDf.js";import{v as _e,B as be,aZ as we,a_ as Ce,a$ as Se,b0 as Ie,b1 as Te,b2 as Ne,b3 as Pe,b4 as xe,b5 as Ae}from"./java-modules-B9jblDzU.js";import{e as Ee}from"./brand-DE-sObfq.js";import{c as re}from"./categorized-timers-JPA-olTr.js";const Fe=u=>u==="SUCCESS"||u==="FAILED";function De(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(b=>typeof b=="number"&&b>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??Fe,b=u.getIntervalMs??_e,d=m(De(u.storageKey)),_=m({}),o=m(!1);let c=null,S=!1;function R(){Ue(u.storageKey,d.value)}function O(n){!Number.isFinite(n)||n<=0||d.value.includes(n)||(d.value=[...d.value,n],R(),E(!0))}function D(n){if(d.value.includes(n)&&(d.value=d.value.filter(r=>r!==n),R(),_.value[n])){const r={..._.value};delete r[n],_.value=r}}function T(n){const r=Array.from(new Set(n.filter(M=>Number.isFinite(M)&&M>0)));d.value=r,R()}function w(n){const r=_.value[n];return!!r&&g(r)}async function N(){if(S)return;const n=d.value.filter(r=>r>0);if(n.length){o.value=!0;try{const M=(await u.fetchProgress(n))?.items||[],K=[],j={..._.value};for(const C of M){const F=u.extractTaskId(C);if(typeof F!="number"||F<=0)continue;const q=u.extractStatus(C)||"";try{u.onUpdate?.(F,C)}catch{}q&&(j[F]=q,g(q)&&K.push({taskId:F,detail:C,status:q}))}_.value=j;for(const C of K){D(C.taskId);try{await u.onTerminal?.(C.taskId,C.detail,C.status)}catch{}}}catch(r){u.onError?.(r)}finally{o.value=!1}}}function L(){c!=null&&(k.clearTimer("task-poll",c),c=null)}function A(n=!1){if(S||c!=null&&!n)return;L();const r=async()=>{if(c=null,!S&&d.value.length){if(o.value){c=k.setTimeout("task-poll",r,500);return}await N(),!S&&d.value.length>0&&(c=k.setTimeout("task-poll",r,b()))}};n?r():c=k.setTimeout("task-poll",r,b())}function E(n=!1){S||d.value.length&&(c!=null&&!n||A(n))}function U(){L()}fe(d,(n,r)=>{if(!S){if(!n.length){U();return}(!r||r.length===0)&&A(!0)}},{flush:"post"});let P=null;typeof document<"u"&&(P=()=>{document.visibilityState==="visible"&&d.value.length>0&&A(!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&&A(!0),{taskIds:d,taskStatuses:_,inFlight:o,add:O,remove:D,reset:T,ensure:E,stop:U,refreshOnce:N,isTerminal:w,dispose:I}}const Be={class:"page-shell module-page"},Re={class:"main-content"},Le={class:"left-panel"},Me={class:"upload-zone"},qe={class:"selected-files"},Oe={key:0,class:"more-line"},Ge={key:1},Ve={class:"filter-zone"},ze={class:"filter-row"},Ke={class:"range-inputs"},je={class:"filter-checks"},He={class:"filter-check-row"},Je={class:"filter-check-row"},Ye={class:"filter-check-row"},Qe={class:"section-title country-section-title"},Ze={key:0,class:"country-pref-saving"},We={class:"country-pref-radios"},Xe=["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"},_t={class:"files"},bt={class:"files"},wt={class:"files"},Ct={class:"files"},St={class:"task-right"},It={class:"status running"},Tt=["onClick"],Nt={class:"result-list-wrap"},Pt={key:0,class:"empty-tasks"},xt={key:1,class:"task-list clean-result-list"},At={class:"left"},Et={class:"id"},Ft={class:"files"},Dt={class:"files"},Ut={class:"files"},$t={class:"files"},Bt={class:"files"},Rt={key:0,class:"files"},Lt={key:1,class:"files"},Mt={class:"task-right"},qt=["onClick"],Ot="brand:collect-data:polling-task-ids",Gt=ve({__name:"BrandCollectDataTab",setup(u){const k=[{code:"DE",label:"德国"},{code:"UK",label:"英国"},{code:"FR",label:"法国"},{code:"IT",label:"意大利"},{code:"ES",label:"西班牙"}],g=m([]),b=m([]),d=m(!1),_=m(!1),o=ye({minAmount:null,maxAmount:null,rank:!1,fba:!1,fbm:!1}),c=m("DE"),S=le(()=>c.value?[c.value]:[]),R=m(!1),O=m(!1),D=re("collect-data-tab");let T=null;const w=m(null),N=m(null),L=m(""),A=m(""),E=m({pendingTaskCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),U=m([]),P=m([]),I=m({}),n=$e({scope:"collect-data-tab",storageKey:Ot,fetchProgress:a=>Ae(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([G(),H()])}}),r=le(()=>g.value.slice(0,8));function M(a){k.some(e=>e.code===a)&&c.value!==a&&(R.value=!0,c.value=a,K())}function K(){T!=null&&D.clearTimer("country-pref-save",T),T=D.setTimeout("country-pref-save",()=>{T=null,j()},450)}async function j(){if(c.value){O.value=!0;try{await we([c.value])}catch(a){y.error(a instanceof Error?a.message:"保存国家顺序失败")}finally{O.value=!1}}}async function C(){try{const a=await Ce();if(R.value)return;const e=a?.country_codes;Array.isArray(e)&&e.length&&(c.value=String(e[0]||"DE"))}catch{}}async function F(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,i=await e.upload_file_to_java(x,$);if(!i?.success||!i.data)throw new Error(i?.error||i?.message||`上传失败:${x}`);s.push(i.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 F(e);b.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 Ee(e);if(!s.success||!s.items?.length){y.warning(s.error||"该文件夹下没有可用的 xlsx 文件");return}const p=await F(s.items);b.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 X(){const a=o.minAmount===null||o.minAmount===void 0||Number.isNaN(o.minAmount)?null:o.minAmount,e=o.maxAmount===null||o.maxAmount===void 0||Number.isNaN(o.maxAmount)?null:o.maxAmount;return{amount:e??a,minAmount:a,maxAmount:e,min_amount:a,max_amount:e,rank:!!o.rank,fba:!!o.fba,fbm:!!o.fbm,countryCodes:[...S.value],countryCode:c.value,country_code:c.value}}async function ue(){if(!b.value.length){y.warning("请先选择 Excel 文件");return}if(!c.value){y.warning("请选择采集国家");return}d.value=!0;try{const a=await Se({files:b.value.map(e=>({fileKey:e.fileKey,originalFilename:e.originalFilename,relativePath:e.relativePath})),task_type:"collect-data",filters:X()});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([G(),H()])}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}_.value=!0;try{await Ie(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:X()}},s=await a.enqueue_json(e);if(!s?.success)throw new Error(s?.error||"入队失败");L.value=`已推送至 Python 队列(队列长度:${s.queue_size??"-"}`,A.value=JSON.stringify(e,null,2),w.value&&n.add(w.value),y.success("已推送到 Python 队列"),await G()}catch(e){y.error(e instanceof Error?e.message:"推送失败")}finally{_.value=!1}}function Z(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"),i=String(e.getMinutes()).padStart(2,"0"),h=String(e.getSeconds()).padStart(2,"0");return`${s}-${p}-${x} ${$}:${i}:${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 G(){try{E.value=await Te()}catch{}}async function H(){try{const e=(await Ne(50)).items||[],s=e.filter(i=>{const h=(i.taskStatus||"").toUpperCase();return h==="PENDING"||h==="RUNNING"});P.value=e.filter(i=>{const h=(i.taskStatus||"").toUpperCase();return h==="SUCCESS"||h==="FAILED"});const p=new Set;for(const i of s)i.taskId&&(p.add(i.taskId),n.add(i.taskId));for(const i of[...n.taskIds.value])e.some(J=>J.taskId===i)||n.remove(i);const x=new Set(s.map(i=>i.taskId).filter(i=>typeof i=="number")),$=[...s];for(const i of n.taskIds.value){if(x.has(i))continue;const h=I.value[i],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 Pe(a.resultId);else if(a.taskId)await xe(a.taskId);else return;a.taskId&&n.remove(a.taskId),y.success("已删除"),await Promise.all([G(),H()])}catch(e){y.error(e instanceof Error?e.message:"删除失败")}}return pe(()=>{C(),G(),H()}),oe(()=>{T!=null&&(D.clearTimer("country-pref-save",T),T=null),D.clearScope()}),(a,e)=>(f(),v("div",Be,[me(be,{active:"collect-data"}),t("div",Re,[t("aside",Le,[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(V,{key:0},[(f(!0),v(V,null,Y(r.value,s=>(f(),v("span",{key:s},l(s),1))),128)),g.value.length>r.value.length?(f(),v("span",Oe," 还有 "+l(g.value.length-r.value.length)+" 个文件未展开显示 ",1)):B("",!0)],64)):(f(),v("span",Ge,"暂未选择文件"))])]),e[14]||(e[14]=t("div",{class:"section-title"},"筛选条件",-1)),t("div",Ve,[t("div",ze,[e[7]||(e[7]=t("label",{class:"filter-label"},"金额区间",-1)),t("div",Ke,[z(t("input",{"onUpdate:modelValue":e[0]||(e[0]=s=>o.minAmount=s),type:"number",step:"0.01",min:"0",class:"filter-input",placeholder:"最低"},null,512),[[ae,o.minAmount,void 0,{number:!0}]]),e[6]||(e[6]=t("span",{class:"range-separator"},"至",-1)),z(t("input",{"onUpdate:modelValue":e[1]||(e[1]=s=>o.maxAmount=s),type:"number",step:"0.01",min:"0",class:"filter-input",placeholder:"最高"},null,512),[[ae,o.maxAmount,void 0,{number:!0}]])])]),t("div",je,[t("label",He,[z(t("input",{type:"checkbox",class:"filter-check-input","onUpdate:modelValue":e[2]||(e[2]=s=>o.rank=s)},null,512),[[W,o.rank]]),e[8]||(e[8]=t("span",{class:"filter-check-text"},"排名",-1))]),t("label",Je,[z(t("input",{type:"checkbox",class:"filter-check-input","onUpdate:modelValue":e[3]||(e[3]=s=>o.fba=s)},null,512),[[W,o.fba]]),e[9]||(e[9]=t("span",{class:"filter-check-text"},"FBA",-1))]),t("label",Ye,[z(t("input",{type:"checkbox",class:"filter-check-input","onUpdate:modelValue":e[4]||(e[4]=s=>o.fbm=s)},null,512),[[W,o.fbm]]),e[10]||(e[10]=t("span",{class:"filter-check-text"},"FBM",-1))])])]),t("div",Qe,[e[11]||(e[11]=t("span",null,"采集国家",-1)),O.value?(f(),v("span",Ze,"保存中…")):B("",!0)]),e[15]||(e[15]=t("p",{class:"hint country-pref-hint"}," 每次任务只采集一个国家,选择后会自动保存,下次进入默认使用该国家。 ",-1)),t("div",We,[(f(),v(V,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,Xe),t("span",et,l(s.label)+""+l(s.code)+"",1)],2)),64))]),t("div",tt,[t("button",{type:"button",class:"btn-run",disabled:d.value||!b.value.length,onClick:ue},l(d.value?"提交中...":"提交采集任务"),9,st),t("button",{type:"button",class:"btn-run btn-queue",disabled:_.value||!w.value,onClick:ce},l(_.value?"推送中...":"推送到 Python 队列"),9,at)]),e[16]||(e[16]=t("p",{class:"loading-msg"},"提交后由 Java 解析 Excel 并落库为待采集任务PENDING推送到 Python 队列将激活任务RUNNINGPython 端按 50 条/页拉取明细执行采集。",-1)),L.value?(f(),v("div",nt,[e[12]||(e[12]=t("div",{class:"section-title queue-debug-title"},"推送结果",-1)),t("div",lt,l(L.value),1),A.value?(f(),v("pre",ot,l(A.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,l(E.value.pendingTaskCount),1)]),t("div",dt,[e[18]||(e[18]=t("span",{class:"summary-label"},"已结束任务",-1)),t("strong",null,l(E.value.processedTaskCount),1)]),t("div",ft,[e[19]||(e[19]=t("span",{class:"summary-label"},"成功任务",-1)),t("strong",null,l(E.value.successTaskCount),1)]),t("div",vt,[e[20]||(e[20]=t("span",{class:"summary-label"},"失败任务",-1)),t("strong",null,l(E.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(V,null,Y(U.value,s=>(f(),v("li",{key:`cur-${s.taskId}`,class:"task-item"},[t("div",ht,[t("span",kt,l(s.sourceFilename||"采集数据"),1),t("div",gt,"任务 ID"+l(s.taskId),1),t("div",_t,"开始时间:"+l(Z(s.startedAt||s.createdAt)),1),t("div",bt,"行数:"+l(s.rowCount??"-"),1),t("div",wt,"总数据去重过滤:"+l(s.dedupeFilteredCount??0),1),t("div",Ct,"不符合 ASIN 过滤:"+l(s.invalidFilteredCount??0),1)]),t("div",St,[t("span",It,l(te(s)),1),t("button",{type:"button",class:"btn-delete",onClick:p=>se(s)},"删除",8,Tt)])]))),128))])):(f(),v("div",mt,"暂无当前任务"))]),t("div",Nt,[e[22]||(e[22]=t("div",{class:"result-list-header"},[t("span",null,"历史记录")],-1)),P.value.length?(f(),v("ul",xt,[(f(!0),v(V,null,Y(P.value,s=>(f(),v("li",{key:`his-${s.resultId}-${s.taskId}`,class:"task-item"},[t("div",At,[t("span",Et,l(s.sourceFilename||"采集数据"),1),t("div",Ft,"任务 ID"+l(s.taskId??"-"),1),t("div",Dt,"开始时间:"+l(Z(s.startedAt||s.createdAt)),1),t("div",Ut,"结束时间:"+l(Z(s.finishedAt)),1),t("div",$t,"总数据去重过滤:"+l(s.dedupeFilteredCount??0),1),t("div",Bt,"不符合 ASIN 过滤:"+l(s.invalidFilteredCount??0),1),s.resultFilename?(f(),v("div",Rt,l(s.resultFilename),1)):B("",!0),s.error?(f(),v("div",Lt,"错误:"+l(s.error),1)):B("",!0)]),t("div",Mt,[t("span",{class:ne(["status",de(s)])},l(te(s)),3),s.resultId?(f(),v("button",{key:0,type:"button",class:"btn-delete",onClick:p=>se(s)},"删除",8,qt)):B("",!0)])]))),128))])):(f(),v("div",Pt,"暂无历史记录"))])])])])]))}}),Vt=he(Gt,[["__scopeId","data-v-8eb7a5b8"]]);ke(Vt).use(ge).mount("#app");