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