2 lines
16 KiB
JavaScript
2 lines
16 KiB
JavaScript
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 队列将激活任务(RUNNING),Python 端按 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");
|