Files
crawler-plugin/app/assets/collect-data.js

2 lines
17 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,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 队列将激活任务RUNNINGPython 端按 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");