2 lines
33 KiB
JavaScript
2 lines
33 KiB
JavaScript
import{d as zt,o as Qt,I as Yt,a as i,c as d,b as S,B as Xt,e as n,w as rt,s as ut,au as Zt,f as k,F as U,u as ce,r as de,t as v,R as es,S as ts,T as V,U as ss,V as as,W as it,n as ye,Y as ns,g as f,h as B,i as X,E as r,av as os,aw as ls,ax as rs,ay as us,az as is,aA as cs,aB as ds,aC as vs,aD as fs,aE as ct,aF as ps,aG as ms,aH as hs,aI as ys,aJ as ws,Q as ks,aK as gs,aL as _s,aM as Is,aN as dt,_ as bs,p as Ss,q as Cs}from"./pywebview-CeWJDVeG.js";/* empty css */import{e as Ts}from"./brand-UU-ckLq6.js";const Ns={class:"page-shell module-page"},Es={class:"main-content"},Ps={class:"left-panel"},As={class:"mode-zone"},Rs={class:"mode-check-row"},xs=["checked"],Ls={class:"mode-check-row"},Ms=["checked"],Ds={class:"mode-zone"},$s={class:"mode-check-row"},Fs={class:"mode-check-row"},Us={key:0,class:"loop-round-input"},Bs={class:"upload-zone"},Os={class:"selected-files clean-placeholder"},qs={key:1,class:"text-muted"},js={class:"input-zone"},Js={class:"input-row"},Ks=["disabled"],Hs={key:0,class:"empty-candidates"},Vs={key:1,class:"candidate-table-scroll"},Ws=["onClick"],Gs={class:"country-pref-checks"},zs=["checked","disabled","onChange"],Qs={class:"country-check-text"},Ys={key:2,class:"country-order-panel"},Xs={class:"country-order-list"},Zs=["onDragstart","onDrop"],ea={class:"country-drag-label"},ta={key:3,class:"country-pref-status"},sa={key:4,class:"mode-status-bar"},aa={class:"run-row"},na=["disabled"],oa=["disabled"],la={key:5,class:"loop-status-card"},ra={class:"loop-status-line"},ua={class:"loop-status-line"},ia={class:"loop-status-line"},ca={class:"loop-status-line"},da={key:0,class:"loop-status-line loop-error"},va=["disabled"],fa={key:6,class:"queue-debug-card"},pa={class:"queue-debug-line"},ma={key:0,class:"queue-debug-payload"},ha={class:"right-panel"},ya={class:"task-list-wrap"},wa={class:"clean-result-summary pr-summary"},ka={class:"summary-card"},ga={class:"summary-card"},_a={class:"summary-card"},Ia={class:"summary-card"},ba={key:0,class:"empty-tasks narrow"},Sa=["onClick"],Ca={class:"result-list-wrap"},Ta={key:0,class:"empty-tasks"},Na={key:0,class:"result-subsection"},Ea={class:"task-list clean-result-list"},Pa={class:"left split-result-main"},Aa={key:0,class:"files"},Ra=["title"],xa={class:"files"},La={key:1,class:"files"},Ma={key:2,class:"files"},Da={class:"task-right split-result-actions"},$a=["onClick"],Fa=["onClick"],Ua={key:1,class:"result-subsection"},Ba={class:"task-list clean-result-list"},Oa={class:"left split-result-main"},qa={key:0,class:"files"},ja=["title"],Ja={class:"files"},Ka={key:1,class:"files"},Ha={key:2,class:"files"},Va={class:"task-right split-result-actions"},Wa=["onClick"],Ga=["onClick"],za=zt({__name:"BrandPriceTrackTab",setup(Ya){const Fe=[{code:"DE",label:"德国"},{code:"UK",label:"英国"},{code:"FR",label:"法国"},{code:"IT",label:"意大利"},{code:"ES",label:"西班牙"}],Z=f(""),we=f([]),Ue=f([]),b=f([]),ve=f(!1),fe=f(!1),O=f(!1),ke=f(!1),Be=f(!1),p=f(""),W=f(""),ge=f({}),q=f("FINITE"),pe=f(1),m=f(null),w=f(null),_e=f(!1),ee=f(!1),P=f(!0),C=f(!1),A=f([]),te=f([]),Ie=B(()=>P.value||C.value),vt=B(()=>{const e=w.value?.status||"";return e==="SUCCESS"||e==="FAILED"||e==="STOPPED"}),be=B(()=>!!m.value&&!vt.value),ft=B(()=>{const e=w.value;if(!e)return"";const t=e.currentRound||1;if(e.executionMode==="INFINITE")return`第 ${t} 轮(无限)`;const s=Math.max(1,e.targetRounds||pe.value||1);return`第 ${t}/${s} 轮`}),h=f(["DE","UK","FR","IT","ES"]),se=f(null),Se=f(!1),Oe=f(!1);let G=null;const ae=f({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),j=f([]),g=f([]),N=f({}),_=f({}),R=f(null),Ce=f(!1);function ne(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function qe(){return`price-track:tasks:${ne()}`}function je(){return`price-track:task-status:${ne()}`}function Je(){return`price-track:tasks-batch-snapshot:${ne()}`}function Ke(){return`price-track:matched-items:${ne()}`}function He(){return`price-track:active-loop:${ne()}`}function oe(e,t,s){if(!(typeof window>"u"))try{s?window.localStorage.removeItem(e):window.localStorage.setItem(e,JSON.stringify(t))}catch{}}function pt(){try{const e=typeof window<"u"?window.localStorage.getItem(qe()):null;if(!e){g.value=[];return}const t=JSON.parse(e);g.value=Array.isArray(t)?t.filter(s=>typeof s=="number"&&s>0):[]}catch{g.value=[]}}function Ve(){oe(qe(),g.value,g.value.length===0)}function mt(){try{const e=typeof window<"u"?window.localStorage.getItem(je()):null;if(!e)return;const t=JSON.parse(e),s={};for(const[l,o]of Object.entries(t)){const u=Number(l);u>0&&typeof o=="string"&&(s[u]=o)}N.value=s}catch{}}function le(){oe(je(),N.value,Object.keys(N.value).length===0)}function ht(){try{const e=typeof window<"u"?window.localStorage.getItem(Je()):null;if(!e)return;const t=JSON.parse(e),s={};for(const[l,o]of Object.entries(t)){const u=Number(l);u>0&&o&&typeof o=="object"&&(s[u]=o)}_.value=s}catch{}}function re(){oe(Je(),_.value,Object.keys(_.value).length===0)}function yt(){try{const e=typeof window<"u"?window.localStorage.getItem(Ke()):null;if(!e)return;const t=JSON.parse(e);Array.isArray(t)&&(b.value=t)}catch{}}function me(){oe(Ke(),b.value,b.value.length===0)}function wt(){try{const e=typeof window<"u"?window.localStorage.getItem(He()):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 z(){oe(He(),m.value,!m.value)}async function kt(){const e=X();if(e?.select_files){const t=await e.select_files({filters:[{name:"Excel/CSV",extensions:"xlsx,xls,csv"}],multiple:!0});t?.paths?.length&&(A.value=t.paths,te.value=await Te(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;A.value=t,te.value=await Te(t),r.success(`已选择 ${t.length} 个ASIN文件`);return}r.warning("当前环境不支持文件选择,请在本地客户端中打开")}async function gt(){const e=X();if(!e?.select_brand_folder){r.warning("当前环境不支持文件夹选择,请在本地客户端中打开");return}try{const t=await e.select_brand_folder();if(!t)return;const s=await Ts(t);if(!s.success||!s.items?.length){r.warning(s.error||"该文件夹下没有可用的 xlsx 文件");return}A.value=s.items.map(l=>l.relativePath||l.absolutePath),te.value=await Te(s.items),r.success(`已选择文件夹内 ${s.items.length} 个ASIN文件`)}catch(t){r.error(t instanceof Error?t.message:"选择失败")}}async function Te(e){const t=X();if(!t?.upload_file_to_java)return[];const s=[];for(const l of e){const o=typeof l=="string"?l:l.absolutePath,u=typeof l=="string"?void 0:l.relativePath,a=await t.upload_file_to_java(o,u);if(!a?.success||!a.data)throw new Error(a?.error||a?.message||`上传失败:${o}`);s.push(a.data)}return s}function Ne(){return te.value.length?te.value.map(e=>e.localPath).filter(e=>!!e):A.value}function Ee(e){P.value=e==="status",C.value=e==="asin"}function We(e){return Fe.find(s=>s.code===e)?.label??e}const _t=B(()=>{const e=h.value,t=new Set(e),s=e.map(o=>({code:o,label:We(o)})),l=Fe.filter(o=>!t.has(o.code)).map(o=>({code:o.code,label:o.label}));return[...s,...l]});function It(e){return h.value.includes(e)}function Ge(e){return h.value.length===1&&h.value[0]===e}function bt(e,t){const s=t.target;if(s){if(!s.checked&&Ge(e)){s.checked=!0,r.warning("至少保留 1 个国家");return}St(e,s.checked)}}function St(e,t){if(Oe.value=!0,t)h.value.includes(e)||(h.value=[...h.value,e]);else{if(h.value.length<=1){r.warning("至少保留 1 个国家");return}h.value=h.value.filter(s=>s!==e)}ze()}function Ct(e){se.value=e}function Tt(){se.value=null}function Nt(e){const t=se.value;if(se.value=null,t==null||t===e)return;Oe.value=!0;const s=[...h.value],[l]=s.splice(t,1);s.splice(e,0,l),h.value=s,ze()}function ze(){G&&clearTimeout(G),G=setTimeout(()=>{G=null,Et()},450)}async function Et(){if(!(h.value.length<1)){Se.value=!0;try{await os(h.value)}catch(e){r.error(e instanceof Error?e.message:"保存国家顺序失败")}finally{Se.value=!1}}}async function Pt(){try{const e=await ls();e?.countryCodes?.length&&(h.value=[...e.countryCodes])}catch{}}async function Pe(){try{we.value=await rs()}catch(e){r.error(e instanceof Error?e.message:"加载备选失败")}}async function x(){try{ae.value=await us()}catch{}}async function M(){try{const e=await is();j.value=e.items||[]}catch{j.value=[]}}function D(){for(const e of[...g.value])!j.value.some(s=>s.taskId===e)&&!_.value[e]&&K(e)}function At(e){Ue.value=e||[]}async function Qe(){const e=Z.value.trim();if(!e){r.warning("请输入店铺名称");return}ve.value=!0;try{await cs(e),Z.value="",await Pe(),r.success("已加入备选")}catch(t){r.error(t instanceof Error?t.message:"保存失败")}finally{ve.value=!1}}async function Rt(e){try{await ds(e.id),await Pe(),b.value=[],me(),r.success("已删除")}catch(t){r.error(t instanceof Error?t.message:"删除失败")}}function xt(){const e=new Set,t=Z.value.trim();t&&e.add(t);for(const s of Ue.value)s?.shopName?.trim()&&e.add(s.shopName.trim());if(C.value)for(const s of A.value){const l=(s||"").trim();if(!l)continue;const u=(l.split(/[/\\]/).filter(Boolean).pop()||"").replace(/\.[^.]+$/,"").trim();u&&e.add(u)}return[...e]}async function Lt(){const e=xt();if(!e.length){r.warning("请勾选备选店铺,或在输入框中填写店名");return}if(C.value&&!A.value.length){r.warning("请先选择 ASIN 文件");return}fe.value=!0;try{const t=await vs(e,{asinFiles:C.value?Ne():[],countryCodes:[...h.value]}),s=t.items||[];ge.value=t.asinRowsByCountry||{};const l=new Map(b.value.map(o=>[(o.shopName||"").trim(),o]));for(const o of s)l.set((o.shopName||"").trim(),o);b.value=[...l.values()],me(),Be.value&&Ot(),r.success(`匹配 ${s.length} 个店铺`)}catch(t){r.error(t instanceof Error?t.message:"匹配失败")}finally{fe.value=!1}}function Mt(e){const t=(e||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[t]||t||"—"}function Dt(e){const t=(e.matchMessage||"").trim();return t||(e.matched&&e.matchStatus==="MATCHED"?"紫鸟索引已命中,可推送队列":e.matched?"已关联索引,请结合状态列查看是否可推送":"未命中或未就绪,请检查店铺名与索引刷新")}function Ae(e){return`${(e.shopName||"").trim()}${e.shopId??""}`}function Ye(e){const t=e instanceof Error?e.message:String(e||"");return/记录不存在|不存在|已删除|not\s*found|404/i.test(t)}function $t(){const e=P.value&&!C.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 J(e){if(!e.length)return;const t=new Set(e.map(l=>Ae(l))),s=new Set(e.map(l=>(l.shopName||"").trim()).filter(l=>!!l));b.value=b.value.filter(l=>{const o=Ae(l),u=(l.shopName||"").trim();return!t.has(o)&&(!u||!s.has(u))}),me()}function Ft(e){j.value=j.value.filter(t=>!(e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId))}async function Ut(e){const t=[...b.value];J([e]);const s=(e.shopName||"").trim();if(!s){r.success("已从匹配结果中移除");return}try{(await fs(s))?.removed&&(await M(),await x(),D()),r.success("已从匹配结果中移除")}catch(l){if(Ye(l)){await M(),await x(),D(),r.success("后端记录已不存在,已同步移除本地记录");return}b.value=t,me(),r.error(l instanceof Error?l.message:"同步后端失败")}}function Xe(e,t){const s=e.items?.[0],l=(t.shopName||"").trim(),o=t.skipAsins||e.skipAsinsByCountry||{},u=e.skipAsinDetailsByCountry||{},a=e.minimumPriceByCountryAndAsin||{},c=$t(),T=s?.resultId??null,F=s?.loopRunId??null,Y=s?.roundIndex??null,y=s?.taskStatus||"RUNNING",L=s?.success??!1,E=s?.error||null,I=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:l,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:L,error:E,output_filename:I,download_url:H,task_status:y,loop_run_id:F,round_index:Y,country_codes:[...h.value],mode:P.value?"status":"asin",skip_asins:o,skip_asins_by_country:o,skip_asin_details_by_country:u,minimum_price_by_country_and_asin:a,skip_asin_delete_policy:c,delete_skip_asin_when_price_below_minimum:c.deleteWhenPriceBelowMinimum,deleteSkipAsinWhenPriceBelowMinimum:c.deleteWhenPriceBelowMinimum,asin_rows_by_country:Object.keys(ge.value).length?ge.value:e.asinRowsByCountry||{},taskId:e.taskId,resultId:T,shopName:l,shopId:t.shopId??null,platformName:t.platform||"",companyName:t.companyName||"",shopMallName:t.shopMallName||"",matchStatus:t.matchStatus||"",matchMessage:t.matchMessage||null,outputFilename:I,downloadUrl:H,taskStatus:y,loopRunId:F,roundIndex:Y}}}async function Ze(e){let t=0;const s=30;for(;;){try{const l=await dt([e]);if(t>0&&(p.value=`任务 ${e} 后端已恢复,继续等待执行结果...`),t=0,(l.missingTaskIds||[]).includes(e))return K(e),await M(),await x(),D(),"FAILED";const o=(l.items||[]).find(a=>a.task?.id===e),u=o?.task?.status||"";if(o){const a=_.value[e];_.value={..._.value,[e]:a?{...a,task:{...a.task||{},...o.task||{}}}:o},re()}if(u&&(N.value={...N.value,[e]:u},le()),u==="SUCCESS"||u==="FAILED")return K(e),await M(),await x(),D(),u}catch(l){const o=(l instanceof Error?l.message:String(l||"")).toLowerCase();if(!["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(a=>o.includes(a.toLowerCase())))throw l;if(t+=1,t>=s)throw new Error(`任务 ${e} 等待后端恢复超时,请稍后手动刷新查看状态`);p.value=`任务 ${e} 运行中,正在等待后端服务恢复(${t}/${s})...`,(t===1||t%5===0)&&r.warning(`任务 ${e} 运行中,后端服务暂时不可用,正在自动重试`),await new Promise(a=>{window.setTimeout(()=>a(),$())});continue}await new Promise(l=>{window.setTimeout(()=>l(),$())})}}function Bt(){return b.value.find(e=>e.matched)}async function Ot(){if(ke.value)return;if(!Ie.value){r.warning("请至少选择一个跟价模式");return}if(C.value&&!A.value.length){r.warning("请先选择 ASIN 文件");return}const e=X();if(!e?.enqueue_json){r.error("当前环境未启用 pywebview enqueue_json");return}if(!b.value.filter(o=>o.matched).length){r.warning("无可用匹配店铺");return}ke.value=!0,O.value=!0,W.value="";let s=0,l=0;try{let o=0;for(;Be.value;){const u=Bt();if(!u)break;o+=1;try{let a=0;const c=await(async()=>{for(;;)try{return await ct({userId:0,statusMode:P.value,asinMode:C.value,items:[u],asinFiles:Ne(),countryCodes:[...h.value]})}catch(y){const L=(y instanceof Error?y.message:String(y||"")).toLowerCase(),E=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(I=>L.includes(I.toLowerCase()));if(a+=1,!E||a>=10)throw y;p.value="后端服务暂时不可用,正在重试创建任务("+a+"/10)...",await new Promise(I=>{window.setTimeout(()=>I(),$())})}})();_.value={..._.value,[c.taskId]:{task:{id:c.taskId,status:"RUNNING"},items:c.items}},N.value={...N.value,[c.taskId]:"RUNNING"},re(),le();const T=Xe(c,u);W.value=JSON.stringify(T,null,2);const F=await e.enqueue_json(T);if(!F?.success){l+=1,p.value="任务 "+c.taskId+" 推送失败,已自动继续下一条:"+(F?.error||"未知错误"),r.error(p.value),J([u]);continue}if(he(c.taskId),Q(!0),J([u]),p.value="任务 "+c.taskId+" 已入队,等待执行完成",await Ze(c.taskId)!=="SUCCESS"){l+=1,p.value="任务 "+c.taskId+" 执行失败,已自动继续下一条",r.error(p.value);continue}s+=1,p.value="任务 "+c.taskId+" 已完成"}catch(a){l+=1,p.value="第 "+o+" 条任务处理失败,已自动继续下一条:"+(a instanceof Error?a.message:"未知错误"),r.error(p.value),J([u]);continue}}(s>0||l>0)&&r.success("店铺任务推送已完成:成功 "+s+" 条,失败 "+l+" 条")}catch(o){p.value=o instanceof Error?o.message:"推送异常",r.error(p.value)}finally{ke.value=!1,O.value=!1}}function ue(e){w.value=e,m.value=e?.id??null,z()}function ie(){if(!w.value)return;const e=w.value.status||"";(e==="SUCCESS"||e==="FAILED"||e==="STOPPED")&&(w.value=null,m.value=null,z())}async function Re(){if(!m.value)return null;try{const e=await ps(m.value);return ue(e),ie(),w.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(l=>t.includes(l.toLowerCase()))?w.value:(w.value=null,m.value=null,z(),null)}}function qt(e){_.value={..._.value,[e.taskId]:{task:{id:e.taskId,status:"RUNNING"},items:e.items}},N.value={...N.value,[e.taskId]:"RUNNING"},re(),le()}async function jt(){if(!(!m.value||ee.value)){ee.value=!0;try{const e=await ms(m.value);ue(e),ie(),r.success(e.status==="STOPPED"?"循环已停止":"已请求停止,当前子任务完成后将收尾")}catch(e){r.error(e instanceof Error?e.message:"停止循环失败")}finally{ee.value=!1}}}async function xe(e){if(_e.value||(e&&m.value!==e&&(m.value=e,z()),!m.value))return;const t=X();if(!t?.enqueue_json)throw new Error("当前环境未启用 pywebview enqueue_json");_e.value=!0;try{for(;m.value;){const s=await Re();if(!s||s.status==="SUCCESS"||s.status==="FAILED"||s.status==="STOPPED")break;if(s.activeTaskId){const y=s.activeTaskId;he(y),Q(!0);const L=await Ze(y);let E=0;const I=await(async()=>{for(;;)try{return await hs(s.id,y)}catch(H){const Wt=(H instanceof Error?H.message:String(H||"")).toLowerCase(),Gt=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some($e=>Wt.includes($e.toLowerCase()));if(E+=1,!Gt||E>=10)throw H;p.value=`循环任务 ${s.id} 等待后端恢复后确认子任务完成(${E}/10)...`,await new Promise($e=>{window.setTimeout(()=>$e(),$())})}})();if(ue(I),await M(),await x(),D(),ie(),L!=="SUCCESS")throw new Error(I.errorMessage||`任务 ${s.activeTaskId} 执行失败`);continue}let l=0;const o=await(async()=>{for(;;)try{return await ys(s.id)}catch(y){const L=(y instanceof Error?y.message:String(y||"")).toLowerCase(),E=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(I=>L.includes(I.toLowerCase()));if(l+=1,!E||l>=10)throw y;p.value=`循环任务 ${s.id} 等待后端恢复后继续派发(${l}/10)...`,await new Promise(I=>{window.setTimeout(()=>I(),$())})}})();if(ue(o.loopRun||s),!o.childTaskRequest){ie();break}const u=o.childTaskRequest,a=u.items?.[0];if(!a)throw new Error("循环任务缺少待执行店铺");let c=0;const T=await(async()=>{for(;;)try{return await ct(u)}catch(y){const L=(y instanceof Error?y.message:String(y||"")).toLowerCase(),E=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(I=>L.includes(I.toLowerCase()));if(c+=1,!E||c>=10)throw y;p.value=`循环任务 ${s.id} 等待后端恢复后重试创建子任务(${c}/10)...`,await new Promise(I=>{window.setTimeout(()=>I(),$())})}})();qt(T);const F=Xe(T,a);W.value=JSON.stringify(F,null,2);const Y=await t.enqueue_json(F);if(!Y?.success)throw new Error(Y?.error||`任务 ${T.taskId} 推送失败`);he(T.taskId),Q(!0),J([a]),p.value=`循环任务 ${s.id} 第 ${o.childTaskRequest.roundIndex||1} 轮已推送:${a.shopName||T.taskId}`}}finally{_e.value=!1}}async function Jt(){if(be.value){try{await xe(m.value||void 0)}catch(t){t instanceof Error&&/子任务不存在|循环任务不存在|404/.test(t.message)&&(w.value=null,m.value=null,z());const s=t instanceof Error?t.message:"循环执行失败";p.value=s,r.error(s)}return}if(!Ie.value){r.warning("请至少选择一个跟价模式");return}if(C.value&&!A.value.length){r.warning("请先选择 ASIN 文件");return}const e=b.value.filter(t=>t.matched);if(!e.length){r.warning("请先匹配可用店铺");return}O.value=!0,W.value="";try{const t=await ws({userId:0,statusMode:P.value,asinMode:C.value,items:e,asinFiles:Ne(),countryCodes:[...h.value],executionMode:q.value,targetRounds:q.value==="FINITE"?Math.max(1,Number(pe.value)||1):void 0});ue(t),p.value=`循环任务 ${t.id} 已创建`,await xe(t.id),ie(),m.value||r.success("跟价循环已启动")}catch(t){const s=t instanceof Error?t.message:"启动循环失败";p.value=s,r.error(s)}finally{O.value=!1}}function $(){return ks()}async function Kt(){const e=g.value.filter(t=>t>0);if(e.length)try{const t=await dt(e);let s=!1;const l={..._.value};for(const o of t.missingTaskIds||[])K(o),delete l[o];for(const o of t.items||[]){const u=o.task?.id,a=o.task?.status;if(typeof u!="number"||u<=0)continue;const c=l[u];l[u]=c?{...c,task:{...c.task||{},...o.task||{}}}:o,a&&(N.value[u]=a,(a==="SUCCESS"||a==="FAILED")&&(K(u),s=!0))}_.value=l,re(),le(),await M(),D(),s&&await x()}catch{}}function Q(e=!1){if(R.value){if(!e)return;window.clearTimeout(R.value),R.value=null}const t=async()=>{if(R.value=null,Ce.value){Q();return}if(g.value.length){Ce.value=!0;try{await Kt()}finally{Ce.value=!1}g.value.length>0&&(R.value=window.setTimeout(t,$()))}};e?t():R.value=window.setTimeout(t,$())}function Ht(){R.value&&(window.clearTimeout(R.value),R.value=null)}function he(e){g.value.includes(e)||(g.value=[...g.value,e],Ve())}function K(e){if(g.value=g.value.filter(t=>t!==e),Ve(),delete N.value[e],le(),_.value[e]){const t={..._.value};delete t[e],_.value=t,re()}}const Le=B(()=>{const e=j.value.filter(s=>s.taskId&&g.value.includes(s.taskId)&&!tt(s.taskId)),t=new Set(e.map(s=>s.taskId).filter(s=>typeof s=="number"));for(const s of g.value){if(t.has(s))continue;const l=_.value[s]?.items?.[0];l&&e.push(l)}return e}),Me=B(()=>j.value.filter(e=>!e.taskId||!g.value.includes(e.taskId)||tt(e.taskId))),Vt=B(()=>Le.value.length>0||Me.value.length>0);function et(e){return e&&(N.value[e]||_.value[e]?.task?.status)||""}function tt(e){const t=et(e);return t==="SUCCESS"||t==="FAILED"}function De(e){const t=e.taskId;return t?et(t)||e.taskStatus||"":e.taskStatus||""}function st(e){const t=De(e);return t==="SUCCESS"?"已完成":t==="FAILED"?"失败":t==="RUNNING"?"执行中":e.success?"已完成":"等待中"}function at(e){const t=De(e);return t==="SUCCESS"||e.success?"success":t==="FAILED"?"failed":"running"}function nt(e){return e.resultId?De(e)==="SUCCESS"||e.success===!0:!1}async function ot(e){if(!e.resultId)return;const t=X(),s=e.outputFilename||`${e.shopName||"result"}.xlsx`;if(!t?.save_file_from_url_new){r.error("当前客户端未提供 save_file_from_url_new,无法下载文件");return}const l=gs(e.resultId),o=await t.save_file_from_url_new(l,s);o.success?r.success(`已保存:${o.path||s}`):o.error&&o.error!=="用户取消"&&r.error(o.error)}async function lt(e){try{e.resultId!=null?await _s(e.resultId):e.taskId!=null&&await Is(e.taskId),w.value&&(e.loopRunId!=null&&e.loopRunId===w.value.id||e.taskId!=null&&e.taskId===w.value.activeTaskId)&&await Re(),e.taskId!=null&&K(e.taskId),J([e]),await M(),await x(),D(),r.success("已删除")}catch(t){if(Ye(t)){e.taskId!=null&&K(e.taskId),J([e]),Ft(e),await x(),D(),r.success("后端记录已不存在,已同步移除本地记录");return}r.error(t instanceof Error?t.message:"删除失败")}}return Qt(()=>{!P.value&&!C.value&&Ee("status"),pt(),mt(),ht(),yt(),wt(),Pe().catch(()=>{}),Pt().catch(()=>{}),M().catch(()=>{}),x().catch(()=>{}),g.value.length&&Q(!0),m.value&&Re().then(e=>{e?.activeTaskId&&(he(e.activeTaskId),Q(!0)),e&&e.status!=="SUCCESS"&&e.status!=="FAILED"&&e.status!=="STOPPED"&&xe(e.id)}).catch(()=>{m.value=null,z()})}),Yt(()=>{Ht(),G&&clearTimeout(G)}),(e,t)=>{const s=Zt,l=ts,o=ss,u=as;return i(),d("div",Ns,[S(Xt,{active:"pricing"}),n("div",Es,[n("aside",Ps,[t[25]||(t[25]=n("div",{class:"section-title"},"跟价模式",-1)),n("div",As,[n("label",Rs,[n("input",{type:"radio",name:"price-track-mode",class:"mode-check-input",checked:P.value,onChange:t[0]||(t[0]=a=>Ee("status"))},null,40,xs),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",Ls,[n("input",{type:"radio",name:"price-track-mode",class:"mode-check-input",checked:C.value,onChange:t[1]||(t[1]=a=>Ee("asin"))},null,40,Ms),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[26]||(t[26]=n("div",{class:"section-title"},"执行配置",-1)),n("div",Ds,[n("label",$s,[rt(n("input",{"onUpdate:modelValue":t[2]||(t[2]=a=>q.value=a),type:"radio",class:"mode-check-input",value:"FINITE"},null,512),[[ut,q.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",Fs,[rt(n("input",{"onUpdate:modelValue":t[3]||(t[3]=a=>q.value=a),type:"radio",class:"mode-check-input",value:"INFINITE"},null,512),[[ut,q.value]]),t[13]||(t[13]=n("span",{class:"mode-check-text"},"无限执行",-1)),t[14]||(t[14]=n("span",{class:"mode-hint-inline"},"上一轮全部成功后立即开始下一轮",-1))]),q.value==="FINITE"?(i(),d("div",Us,[t[15]||(t[15]=n("span",{class:"hint"},"轮次",-1)),S(s,{modelValue:pe.value,"onUpdate:modelValue":t[4]||(t[4]=a=>pe.value=a),min:1,max:9999,disabled:be.value||O.value},null,8,["modelValue","disabled"])])):k("",!0)]),C.value?(i(),d(U,{key:0},[t[17]||(t[17]=n("div",{class:"section-title"},[ce("ASIN文档 "),n("span",{class:"tag-badge"},"自定义模式")],-1)),n("div",Bs,[t[16]||(t[16]=n("div",{class:"hint"},"上传包含ASIN的表格文件,按文档内的ASIN进行跟价。",-1)),n("div",{class:"btns"},[n("button",{type:"button",class:"opt-btn",onClick:kt},"选择ASIN文件"),n("button",{type:"button",class:"opt-btn",onClick:gt},"选择文件夹")]),n("div",Os,[A.value.length?(i(!0),d(U,{key:0},de(A.value,(a,c)=>(i(),d("span",{key:c},v(a),1))),128)):(i(),d("span",qs,"暂未选择"))])])],64)):k("",!0),P.value?(i(),d(U,{key:1},[t[19]||(t[19]=n("div",{class:"section-title"},"店铺名称",-1)),n("div",js,[t[18]||(t[18]=n("div",{class:"hint"},"输入店铺名后点「确认」加入下方备选区。可同时配合上方模式使用。",-1)),n("div",Js,[S(l,{modelValue:Z.value,"onUpdate:modelValue":t[5]||(t[5]=a=>Z.value=a),clearable:"",placeholder:"请输入店铺名称",onKeyup:es(Qe,["enter"])},null,8,["modelValue"]),n("button",{type:"button",class:"opt-btn",disabled:ve.value,onClick:Qe},v(ve.value?"保存中…":"确认"),9,Ks)])]),t[20]||(t[20]=n("div",{class:"section-title"},"备选店铺",-1)),we.value.length?(i(),d("div",Vs,[S(u,{data:we.value,"row-key":"id",height:"160",class:"candidate-table",onSelectionChange:At},{default:V(()=>[S(o,{type:"selection",width:"42"}),S(o,{prop:"shopName",label:"店铺名","min-width":"120","show-overflow-tooltip":""}),S(o,{label:"操作",width:"72",align:"center"},{default:V(({row:a})=>[n("button",{type:"button",class:"link-danger",onClick:c=>Rt(a)},"删除",8,Ws)]),_:1})]),_:1},8,["data"])])):(i(),d("div",Hs,"暂无备选店铺,请先输入并确认"))],64)):k("",!0),t[27]||(t[27]=n("div",{class:"section-title"},"处理国家与顺序",-1)),t[28]||(t[28]=n("p",{class:"hint country-pref-hint"}," 勾选需要处理的站点;拖拽调整顺序。设置会按当前登录用户保存。 ",-1)),n("div",Gs,[(i(!0),d(U,null,de(_t.value,a=>(i(),d("label",{key:a.code,class:"country-check-row"},[n("input",{type:"checkbox",class:"country-check-input",checked:It(a.code),disabled:Ge(a.code),onChange:c=>bt(a.code,c)},null,40,zs),n("span",Qs,v(a.label)+"("+v(a.code)+")",1)]))),128))]),h.value.length?(i(),d("div",Ys,[t[22]||(t[22]=n("div",{class:"country-order-caption"},"已选顺序(拖拽 ⋮⋮ 调整)",-1)),n("div",Xs,[(i(!0),d(U,null,de(h.value,(a,c)=>(i(),d("div",{key:a,class:ye(["country-drag-row",{dragging:se.value===c}]),draggable:"true",onDragstart:T=>Ct(c),onDragend:Tt,onDragover:t[6]||(t[6]=it(()=>{},["prevent"])),onDrop:it(T=>Nt(c),["prevent"])},[t[21]||(t[21]=n("span",{class:"drag-handle",title:"拖动排序"},"⋮⋮",-1)),n("span",ea,v(We(a))+"("+v(a)+")",1)],42,Zs))),128))])])):k("",!0),Se.value?(i(),d("div",ta,"保存中…")):k("",!0),P.value?(i(),d("div",sa,[...t[23]||(t[23]=[n("span",{class:"mode-status-dot active"},null,-1),n("span",{class:"mode-status-text"},"商品状态模式:将在售(Active)ASIN纳入跟价,跳过ASIN由后台配置的店铺维度数据提供",-1)])])):k("",!0),n("div",aa,[n("button",{type:"button",class:"btn-run",disabled:fe.value,onClick:Lt},v(fe.value?"匹配中…":"匹配店铺"),9,na),n("button",{type:"button",class:"btn-run btn-queue",disabled:O.value||!Ie.value,onClick:Jt},v(O.value?"推送中…":"推送到 Python 队列"),9,oa)]),t[29]||(t[29]=n("p",{class:"loading-msg"},[ce("上传ASIN文档和多选店铺"),n("strong",null,"可同时生效"),ce(",跟价结果合并输出。全量和自定义的区别仅在于ASIN来源不同。")],-1)),w.value?(i(),d("div",la,[n("div",ra,"循环任务 ID:"+v(w.value.id),1),n("div",ua,"状态:"+v(w.value.status||"-"),1),n("div",ia,"进度:"+v(ft.value),1),n("div",ca,"当前店铺:"+v((w.value.currentShopIndex||0)+1)+"/"+v(w.value.totalShopCount||0),1),w.value.errorMessage?(i(),d("div",da,v(w.value.errorMessage),1)):k("",!0),n("button",{type:"button",class:"opt-btn loop-stop-btn",disabled:!be.value||ee.value,onClick:jt},v(ee.value?"停止中...":"停止循环"),9,va)])):k("",!0),p.value?(i(),d("div",fa,[t[24]||(t[24]=n("div",{class:"section-title queue-debug-title"},"推送结果",-1)),n("div",pa,v(p.value),1),W.value?(i(),d("pre",ma,v(W.value),1)):k("",!0)])):k("",!0)]),n("section",ha,[t[38]||(t[38]=n("div",{class:"panel-header"},"匹配与任务",-1)),n("div",ya,[n("div",wa,[n("div",ka,[t[30]||(t[30]=n("span",{class:"summary-label"},"备选店铺数",-1)),n("strong",null,v(ae.value.candidateCount),1)]),n("div",ga,[t[31]||(t[31]=n("span",{class:"summary-label"},"已结束任务",-1)),n("strong",null,v(ae.value.processedTaskCount),1)]),n("div",_a,[t[32]||(t[32]=n("span",{class:"summary-label"},"成功任务",-1)),n("strong",null,v(ae.value.successTaskCount),1)]),n("div",Ia,[t[33]||(t[33]=n("span",{class:"summary-label"},"失败任务",-1)),n("strong",null,v(ae.value.failedTaskCount),1)])]),t[37]||(t[37]=n("div",{class:"subsection-title"},"匹配结果",-1)),b.value.length?(i(),ns(u,{key:1,data:b.value,"row-key":Ae,"highlight-current-row":!1,class:"result-table match-table"},{default:V(()=>[S(o,{prop:"shopName",label:"店铺名","min-width":"100"}),S(o,{label:"匹配",width:"72",align:"center"},{default:V(({row:a})=>[n("span",{class:ye(a.matched?"ok":"fail")},v(a.matched?"是":"否"),3)]),_:1}),S(o,{prop:"shopId",label:"店铺ID","min-width":"120","show-overflow-tooltip":""}),S(o,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),S(o,{prop:"companyName",label:"公司","min-width":"100","show-overflow-tooltip":""}),S(o,{label:"状态",width:"100","show-overflow-tooltip":""},{default:V(({row:a})=>[ce(v(Mt(a.matchStatus)),1)]),_:1}),S(o,{label:"说明","min-width":"140","show-overflow-tooltip":""},{default:V(({row:a})=>[ce(v(Dt(a)),1)]),_:1}),S(o,{label:"操作",width:"72",align:"center"},{default:V(({row:a})=>[n("button",{type:"button",class:"link-danger",onClick:c=>Ut(a)},"删除",8,Sa)]),_:1})]),_:1},8,["data"])):(i(),d("div",ba,"完成「匹配店铺」后,在此展示紫鸟索引匹配结果,供核对后再推送队列。")),n("div",Ca,[t[36]||(t[36]=n("div",{class:"result-list-header"},[n("span",null,"处理记录")],-1)),Vt.value?(i(),d(U,{key:1},[Le.value.length?(i(),d("div",Na,[t[34]||(t[34]=n("div",{class:"result-subsection-title"},"当前任务",-1)),n("ul",Ea,[(i(!0),d(U,null,de(Le.value,a=>(i(),d("li",{key:`cur-${a.resultId}-${a.taskId}`,class:"task-item split-result-item"},[n("div",Pa,[a.roundIndex?(i(),d("div",Aa,"轮次:第 "+v(a.roundIndex)+" 轮",1)):k("",!0),n("span",{class:"id",title:a.shopName||""},v(a.shopName||"-"),9,Ra),n("div",xa,"任务 ID:"+v(a.taskId??"-"),1),a.platform?(i(),d("div",La,"平台:"+v(a.platform),1)):k("",!0),a.error?(i(),d("div",Ma,"错误:"+v(a.error),1)):k("",!0)]),n("div",Da,[n("span",{class:ye(["status",at(a)])},v(st(a)),3),nt(a)?(i(),d("button",{key:0,type:"button",class:"download",onClick:c=>ot(a)}," 下载 ",8,$a)):k("",!0),n("button",{type:"button",class:"btn-delete",onClick:c=>lt(a)},"删除",8,Fa)])]))),128))])])):k("",!0),Me.value.length?(i(),d("div",Ua,[t[35]||(t[35]=n("div",{class:"result-subsection-title"},"历史记录",-1)),n("ul",Ba,[(i(!0),d(U,null,de(Me.value,a=>(i(),d("li",{key:`his-${a.resultId}-${a.taskId}`,class:"task-item split-result-item"},[n("div",Oa,[a.roundIndex?(i(),d("div",qa,"轮次:第 "+v(a.roundIndex)+" 轮",1)):k("",!0),n("span",{class:"id",title:a.shopName||""},v(a.shopName||"-"),9,ja),n("div",Ja,"任务 ID:"+v(a.taskId??"-"),1),a.outputFilename?(i(),d("div",Ka,"文件:"+v(a.outputFilename),1)):k("",!0),a.error?(i(),d("div",Ha,"错误:"+v(a.error),1)):k("",!0)]),n("div",Va,[n("span",{class:ye(["status",at(a)])},v(st(a)),3),nt(a)?(i(),d("button",{key:0,type:"button",class:"download",onClick:c=>ot(a)}," 下载 ",8,Wa)):k("",!0),n("button",{type:"button",class:"btn-delete",onClick:c=>lt(a)},"删除",8,Ga)])]))),128))])])):k("",!0)],64)):(i(),d("div",Ta,"暂无处理记录。推送队列并等待 Python 回传后,将在此显示下载链接。"))])])])])])}}}),Qa=bs(za,[["__scopeId","data-v-e79e58a9"]]);Ss(Qa).use(Cs).mount("#app");
|