Files
crawler-plugin/new_web_source/assets/price-track.js
2026-04-23 20:48:57 +08:00

2 lines
33 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 Wt,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 G,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"},Ps={class:"main-content"},Es={class:"left-panel"},As={class:"mode-zone"},Rs={class:"mode-check-row"},xs=["checked"],Ds={class:"mode-check-row"},Ls=["checked"],$s={class:"mode-zone"},Ms={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"],Vs={key:0,class:"empty-candidates"},Gs={key:1,class:"candidate-table-scroll"},Hs=["onClick"],zs={class:"country-pref-checks"},Ws=["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"},Pa={class:"task-list clean-result-list"},Ea={class:"left split-result-main"},Aa={key:0,class:"files"},Ra=["title"],xa={class:"files"},Da={key:1,class:"files"},La={key:2,class:"files"},$a={class:"task-right split-result-actions"},Ma=["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"},Va={key:2,class:"files"},Ga={class:"task-right split-result-actions"},Ha=["onClick"],za=["onClick"],Wa=Wt({__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(""),H=f(""),ge=f({}),q=f("FINITE"),pe=f(1),m=f(null),w=f(null),_e=f(!1),ee=f(!1),A=f(!0),T=f(!1),E=f([]),te=f([]),Ie=B(()=>A.value||T.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 z=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 Ve(){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 Ge(){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(Ve()):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 W(){oe(Ve(),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&&(E.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;E.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}E.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):E.value}function Pe(e){A.value=e==="status",T.value=e==="asin"}function He(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:He(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 ze(e){return h.value.length===1&&h.value[0]===e}function bt(e,t){const s=t.target;if(s){if(!s.checked&&ze(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)}We()}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,We()}function We(){z&&clearTimeout(z),z=setTimeout(()=>{z=null,Pt()},450)}async function Pt(){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 Et(){try{const e=await ls();e?.countryCodes?.length&&(h.value=[...e.countryCodes])}catch{}}async function Ee(){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 L(){try{const e=await is();j.value=e.items||[]}catch{j.value=[]}}function $(){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 Ee(),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 Ee(),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(T.value)for(const s of E.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 Dt(){const e=xt();if(!e.length){r.warning("请勾选备选店铺,或在输入框中填写店名");return}if(T.value&&!E.value.length){r.warning("请先选择 ASIN 文件");return}fe.value=!0;try{const t=await vs(e,{asinFiles:T.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 Lt(e){const t=(e||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[t]||t||"—"}function $t(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 Mt(){return{enabled:!1,mode:"NONE",deleteWhenPriceBelowMinimum:!1,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 L(),await x(),$()),r.success("已从匹配结果中移除")}catch(l){if(Ye(l)){await L(),await x(),$(),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=Mt(),C=s?.resultId??null,F=s?.loopRunId??null,Y=s?.roundIndex??null,y=s?.taskStatus||"RUNNING",D=s?.success??!1,P=s?.error||null,I=s?.outputFilename||null,V=s?.downloadUrl||null;return{type:"price-track-run",ts:Date.now(),data:{task_id:e.taskId,result_id:C,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:D,error:P,output_filename:I,download_url:V,task_status:y,loop_run_id:F,round_index:Y,country_codes:[...h.value],mode:A.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:C,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:V,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 L(),await x(),$(),"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 L(),await x(),$(),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(),M())});continue}await new Promise(l=>{window.setTimeout(()=>l(),M())})}}function Bt(){return b.value.find(e=>e.matched)}async function Ot(){if(ke.value)return;if(!Ie.value){r.warning("请至少选择一个跟价模式");return}if(T.value&&!E.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,H.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:A.value,asinMode:T.value,items:[u],asinFiles:Ne(),countryCodes:[...h.value]})}catch(y){const D=(y instanceof Error?y.message:String(y||"")).toLowerCase(),P=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(I=>D.includes(I.toLowerCase()));if(a+=1,!P||a>=10)throw y;p.value="后端服务暂时不可用,正在重试创建任务("+a+"/10...",await new Promise(I=>{window.setTimeout(()=>I(),M())})}})();_.value={..._.value,[c.taskId]:{task:{id:c.taskId,status:"RUNNING"},items:c.items}},N.value={...N.value,[c.taskId]:"RUNNING"},re(),le();const C=Xe(c,u);H.value=JSON.stringify(C,null,2);const F=await e.enqueue_json(C);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,W()}function ie(){if(!w.value)return;const e=w.value.status||"";(e==="SUCCESS"||e==="FAILED"||e==="STOPPED")&&(w.value=null,m.value=null,W())}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,W(),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,W()),!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 D=await Ze(y);let P=0;const I=await(async()=>{for(;;)try{return await hs(s.id,y)}catch(V){const Ht=(V instanceof Error?V.message:String(V||"")).toLowerCase(),zt=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(Me=>Ht.includes(Me.toLowerCase()));if(P+=1,!zt||P>=10)throw V;p.value=`循环任务 ${s.id} 等待后端恢复后确认子任务完成(${P}/10...`,await new Promise(Me=>{window.setTimeout(()=>Me(),M())})}})();if(ue(I),await L(),await x(),$(),ie(),D!=="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 D=(y instanceof Error?y.message:String(y||"")).toLowerCase(),P=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(I=>D.includes(I.toLowerCase()));if(l+=1,!P||l>=10)throw y;p.value=`循环任务 ${s.id} 等待后端恢复后继续派发(${l}/10...`,await new Promise(I=>{window.setTimeout(()=>I(),M())})}})();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 C=await(async()=>{for(;;)try{return await ct(u)}catch(y){const D=(y instanceof Error?y.message:String(y||"")).toLowerCase(),P=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"].some(I=>D.includes(I.toLowerCase()));if(c+=1,!P||c>=10)throw y;p.value=`循环任务 ${s.id} 等待后端恢复后重试创建子任务(${c}/10...`,await new Promise(I=>{window.setTimeout(()=>I(),M())})}})();qt(C);const F=Xe(C,a);H.value=JSON.stringify(F,null,2);const Y=await t.enqueue_json(F);if(!Y?.success)throw new Error(Y?.error||`任务 ${C.taskId} 推送失败`);he(C.taskId),Q(!0),J([a]),p.value=`循环任务 ${s.id}${o.childTaskRequest.roundIndex||1} 轮已推送:${a.shopName||C.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,W());const s=t instanceof Error?t.message:"循环执行失败";p.value=s,r.error(s)}return}if(!Ie.value){r.warning("请至少选择一个跟价模式");return}if(T.value&&!E.value.length){r.warning("请先选择 ASIN 文件");return}const e=b.value.filter(t=>t.matched);if(!e.length){r.warning("请先匹配可用店铺");return}O.value=!0,H.value="";try{const t=await ws({userId:0,statusMode:A.value,asinMode:T.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 M(){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 L(),$(),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,M()))}};e?t():R.value=window.setTimeout(t,M())}function Vt(){R.value&&(window.clearTimeout(R.value),R.value=null)}function he(e){g.value.includes(e)||(g.value=[...g.value,e],Ge())}function K(e){if(g.value=g.value.filter(t=>t!==e),Ge(),delete N.value[e],le(),_.value[e]){const t={..._.value};delete t[e],_.value=t,re()}}const De=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}),Le=B(()=>j.value.filter(e=>!e.taskId||!g.value.includes(e.taskId)||tt(e.taskId))),Gt=B(()=>De.value.length>0||Le.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 $e(e){const t=e.taskId;return t?et(t)||e.taskStatus||"":e.taskStatus||""}function st(e){const t=$e(e);return t==="SUCCESS"?"已完成":t==="FAILED"?"失败":t==="RUNNING"?"执行中":e.success?"已完成":"等待中"}function at(e){const t=$e(e);return t==="SUCCESS"||e.success?"success":t==="FAILED"?"failed":"running"}function nt(e){return e.resultId?$e(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 L(),await x(),$(),r.success("已删除")}catch(t){if(Ye(t)){e.taskId!=null&&K(e.taskId),J([e]),Ft(e),await x(),$(),r.success("后端记录已不存在,已同步移除本地记录");return}r.error(t instanceof Error?t.message:"删除失败")}}return Qt(()=>{!A.value&&!T.value&&Pe("status"),pt(),mt(),ht(),yt(),wt(),Ee().catch(()=>{}),Et().catch(()=>{}),L().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,W()})}),Yt(()=>{Vt(),z&&clearTimeout(z)}),(e,t)=>{const s=Zt,l=ts,o=ss,u=as;return i(),d("div",Ns,[S(Xt,{active:"pricing"}),n("div",Ps,[n("aside",Es,[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:A.value,onChange:t[0]||(t[0]=a=>Pe("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",Ds,[n("input",{type:"radio",name:"price-track-mode",class:"mode-check-input",checked:T.value,onChange:t[1]||(t[1]=a=>Pe("asin"))},null,40,Ls),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",$s,[n("label",Ms,[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)]),T.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,[E.value.length?(i(!0),d(U,{key:0},de(E.value,(a,c)=>(i(),d("span",{key:c},v(a),1))),128)):(i(),d("span",qs,"暂未选择"))])])],64)):k("",!0),A.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",Gs,[S(u,{data:we.value,"row-key":"id",height:"160",class:"candidate-table",onSelectionChange:At},{default:G(()=>[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:G(({row:a})=>[n("button",{type:"button",class:"link-danger",onClick:c=>Rt(a)},"删除",8,Hs)]),_:1})]),_:1},8,["data"])])):(i(),d("div",Vs,"暂无备选店铺,请先输入并确认"))],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",zs,[(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:ze(a.code),onChange:c=>bt(a.code,c)},null,40,Ws),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:C=>Ct(c),onDragend:Tt,onDragover:t[6]||(t[6]=it(()=>{},["prevent"])),onDrop:it(C=>Nt(c),["prevent"])},[t[21]||(t[21]=n("span",{class:"drag-handle",title:"拖动排序"},"⋮⋮",-1)),n("span",ea,v(He(a))+""+v(a)+"",1)],42,Zs))),128))])])):k("",!0),Se.value?(i(),d("div",ta,"保存中…")):k("",!0),A.value?(i(),d("div",sa,[...t[23]||(t[23]=[n("span",{class:"mode-status-dot active"},null,-1),n("span",{class:"mode-status-text"},"商品状态模式将在售ActiveASIN纳入跟价跳过ASIN由后台配置的店铺维度数据提供",-1)])])):k("",!0),n("div",aa,[n("button",{type:"button",class:"btn-run",disabled:fe.value,onClick:Dt},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),H.value?(i(),d("pre",ma,v(H.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:G(()=>[S(o,{prop:"shopName",label:"店铺名","min-width":"100"}),S(o,{label:"匹配",width:"72",align:"center"},{default:G(({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:G(({row:a})=>[ce(v(Lt(a.matchStatus)),1)]),_:1}),S(o,{label:"说明","min-width":"140","show-overflow-tooltip":""},{default:G(({row:a})=>[ce(v($t(a)),1)]),_:1}),S(o,{label:"操作",width:"72",align:"center"},{default:G(({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)),Gt.value?(i(),d(U,{key:1},[De.value.length?(i(),d("div",Na,[t[34]||(t[34]=n("div",{class:"result-subsection-title"},"当前任务",-1)),n("ul",Pa,[(i(!0),d(U,null,de(De.value,a=>(i(),d("li",{key:`cur-${a.resultId}-${a.taskId}`,class:"task-item split-result-item"},[n("div",Ea,[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",Da,"平台:"+v(a.platform),1)):k("",!0),a.error?(i(),d("div",La,"错误:"+v(a.error),1)):k("",!0)]),n("div",$a,[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,Ma)):k("",!0),n("button",{type:"button",class:"btn-delete",onClick:c=>lt(a)},"删除",8,Fa)])]))),128))])])):k("",!0),Le.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(Le.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",Va,"错误:"+v(a.error),1)):k("",!0)]),n("div",Ga,[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,Ha)):k("",!0),n("button",{type:"button",class:"btn-delete",onClick:c=>lt(a)},"删除",8,za)])]))),128))])])):k("",!0)],64)):(i(),d("div",Ta,"暂无处理记录。推送队列并等待 Python 回传后,将在此显示下载链接。"))])])])])])}}}),Qa=bs(Wa,[["__scopeId","data-v-f6430de9"]]);Ss(Qa).use(Cs).mount("#app");