Files
crawler-plugin/new_web_source/assets/shop-match.js
2026-05-12 23:25:12 +08:00

2 lines
31 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import{d as ds,g as m,o as fs,L as hs,a as i,c,b,B as vs,e as l,ak as ps,al as ms,t as v,a4 as A,am as gs,an as ys,F as V,r as K,ao as kt,n as pe,f as E,ap as Ss,a5 as wt,aq as ks,ar as ws,w as _s,v as bs,aG as Ts,x as me,h as ge,aH as Cs,aI as Es,aJ as Is,aK as Ds,E as p,aL as $s,aM as Ns,aN as Ms,i as Fe,aO as Ps,aP as xs,aQ as As,aR as Ls,aS as Us,aT as Re,aU as Fs,U as Rs,_ as Os,aV as Vs,q as Hs,s as Bs}from"./pywebview-ZMN052YE.js";import{z as qs}from"./zh-cn-BXYgxART.js";/* empty css */import{L as zs}from"./listingFilters-BpGOU_pJ.js";/* empty css */import{c as Ks}from"./categorized-timers-JPA-olTr.js";const js={class:"page-shell module-page"},Gs={class:"main-content"},Js={class:"left-panel"},Ys={class:"input-zone"},Qs={class:"input-row"},Ws=["disabled"],Xs={key:0,class:"empty-candidates"},Zs={key:1,class:"candidate-table-scroll"},ea=["onClick"],ta={class:"country-pref-checks"},sa=["checked","disabled","onChange"],aa={class:"country-check-text"},na={key:2,class:"country-order-panel"},oa={class:"country-order-list"},la=["onDragstart","onDrop"],ra={class:"country-drag-label"},ua={key:3,class:"country-pref-status"},ia={class:"listing-filter-row"},ca={class:"schedule-switch"},da=["disabled"],fa={key:4,class:"schedule-config"},ha=["disabled","onClick"],va=["disabled"],pa={class:"run-row"},ma=["disabled"],ga=["disabled"],ya={key:5,class:"queue-debug-card"},Sa={class:"queue-debug-line"},ka={key:0,class:"queue-debug-payload"},wa={class:"right-panel"},_a={class:"task-list-wrap"},ba={class:"clean-result-summary"},Ta={class:"summary-card"},Ca={class:"summary-card"},Ea={class:"summary-card"},Ia={class:"summary-card"},Da={key:0,class:"empty-tasks narrow"},$a=["onClick"],Na={class:"result-list-wrap"},Ma={key:0,class:"empty-tasks"},Pa={key:0,class:"result-subsection"},xa={class:"task-list"},Aa={class:"left split-result-main"},La=["title"],Ua={class:"files"},Fa={key:0,class:"files"},Ra={key:1,class:"files"},Oa={key:2,class:"files"},Va={key:3,class:"files"},Ha={class:"task-right"},Ba=["onClick"],qa=["onClick"],za={key:1,class:"result-subsection"},Ka={class:"task-list"},ja={class:"left split-result-main"},Ga=["title"],Ja={class:"files"},Ya={key:0,class:"files"},Qa={key:1,class:"files"},Wa={class:"task-right"},Xa=["onClick"],Za=["onClick"],en=ds({__name:"BrandShopMatchTab",setup(sn){const ye=[{code:"DE",label:"德国"},{code:"UK",label:"英国"},{code:"FR",label:"法国"},{code:"IT",label:"意大利"},{code:"ES",label:"西班牙"}],ae=m(""),Se=m([]),Oe=m([]),T=m([]),ke=m("Active"),ne=m(!1),oe=m(!1),P=m(!1),we=m(!1),_e=m(!1),S=m(""),j=m(""),g=m(["DE","UK","FR","IT","ES"]),G=m(null),be=m(!1),Te=m(!1);let H=null;const x=m(!0),k=m([$e()]),J=m({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),D=m([]),y=m([]),w=m({}),d=m({}),M=m(null),Ce=m(!1),N=new Map,Ee=m(!1);let Y=null,Ve=0,He="",_=!1;const C=Ks("shop-match"),Ie=ge(()=>Ye(D.value.filter(e=>!!I(e.taskId)&&!Ze(e)),d.value,"current")),De=ge(()=>Ye(D.value.filter(e=>!I(e.taskId)||Ze(e)),d.value,"history")),_t=ge(()=>Ie.value.length>0||De.value.length>0),bt=ge(()=>{const e=new Set(g.value);return[...g.value.map(t=>({code:t,label:Ge(t)})),...ye.filter(t=>!e.has(t.code)).map(t=>({code:t.code,label:t.label}))]});function Q(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function Tt(){const e=Number(Q());return Number.isFinite(e)&&e>0?e:0}function I(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:0}function Be(){return`shop-match:tasks:${Q()}`}function qe(){return`shop-match:task-status:${Q()}`}function ze(){return`shop-match:task-snapshots:${Q()}`}function Ke(){return`shop-match:matched-items:${Q()}`}function le(e,t,s){s?window.localStorage.removeItem(e):window.localStorage.setItem(e,JSON.stringify(t))}function L(e){return`${(e.shopName||"").trim()}::${e.shopId||""}`}function je(e){return`${I(e.taskId)}-${e.resultId||0}-${e.shopName||""}`}function Ge(e){return ye.find(t=>t.code===e)?.label||e}function Ct(e){const t=e.getFullYear(),s=String(e.getMonth()+1).padStart(2,"0"),a=String(e.getDate()).padStart(2,"0"),n=String(e.getHours()).padStart(2,"0"),u=String(e.getMinutes()).padStart(2,"0"),r=String(e.getSeconds()).padStart(2,"0");return`${t}-${s}-${a}T${n}:${u}:${r}`}function re(e){const t=e.getFullYear(),s=String(e.getMonth()+1).padStart(2,"0"),a=String(e.getDate()).padStart(2,"0"),n=String(e.getHours()).padStart(2,"0"),u=String(e.getMinutes()).padStart(2,"0");return`${t}-${s}-${a} ${n}:${u}:00`}function $e(){const e=new Date;return e.setSeconds(0,0),e.setMinutes(e.getMinutes()+5),re(e)}function W(e){if(!e)return null;const s=e.trim().replace("T"," ").match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})(?::(\d{2}))?$/);if(!s)return null;const a=Number(s[1]),n=Number(s[2]),u=Number(s[3]),r=Number(s[4]),f=Number(s[5]),o=Number(s[6]||"0"),h=new Date(a,n-1,u,r,f,o,0);return Number.isNaN(h.getTime())||h.getFullYear()!==a||h.getMonth()!==n-1||h.getDate()!==u?null:h}function Et(e,t){const s=W(e)||new Date;return s.setSeconds(0,0),s.setMinutes(s.getMinutes()+t),re(s)}function Je(e){const t=W(e);if(!t)return"-";const s=String(t.getMonth()+1).padStart(2,"0"),a=String(t.getDate()).padStart(2,"0"),n=String(t.getHours()).padStart(2,"0"),u=String(t.getMinutes()).padStart(2,"0");return`${s}-${a} ${n}:${u}`}function Ye(e,t,s){const a=new Map;for(const n of e)a.set(je(n),n);for(const[n,u]of Object.entries(t)){const r=I(n),f=u.items?.[0];if(!f||!r)continue;const o=Xe(r);if(s==="current"&&o||s==="history"&&!o)continue;const h=je({...f,taskId:r});a.has(h)||a.set(h,{...f,taskId:r})}return Array.from(a.values())}function It(){try{const e=window.localStorage.getItem(Be()),t=e?JSON.parse(e):[];y.value=Array.isArray(t)?t.filter(s=>typeof s=="number"&&s>0):[]}catch{y.value=[]}}function ue(){le(Be(),y.value,y.value.length===0)}function Dt(){try{const e=window.localStorage.getItem(qe());w.value=e?JSON.parse(e):{}}catch{w.value={}}}function U(){le(qe(),w.value,Object.keys(w.value).length===0)}function $t(){try{const e=window.localStorage.getItem(ze());d.value=e?JSON.parse(e):{}}catch{d.value={}}}function B(){le(ze(),d.value,Object.keys(d.value).length===0)}function Nt(){try{const e=window.localStorage.getItem(Ke());T.value=e?JSON.parse(e):[]}catch{T.value=[]}}function Ne(){le(Ke(),T.value,T.value.length===0)}function Mt(e){const t=e instanceof Error?e.message:String(e||"");return/记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(t)}function Pt(){const e=y.value.filter(t=>(w.value[t]||d.value[t]?.task?.status)==="RUNNING");e.length!==y.value.length&&(y.value=e,ue())}function Qe(e){y.value.includes(e)||(y.value=[...y.value,e],ue())}function ie(e){const t=N.get(e);t&&(C.clearTimer("scheduled-dispatch",t),N.delete(e),N.size||fe())}function ce(e){if(ie(e),y.value=y.value.filter(t=>t!==e),delete w.value[e],d.value[e]){const t={...d.value};delete t[e],d.value=t,B()}ue(),U()}function X(e){ce(e),D.value=D.value.filter(t=>I(t.taskId)!==e)}function We(e,t=!0){y.value=y.value.filter(s=>s!==e),t||delete w.value[e],ue(),U()}function Z(e){return e==="SUCCESS"||e==="FAILED"||e==="COMPLETED"}function Xe(e){if(!e)return!1;const t=w.value[e]||d.value[e]?.task?.status;return Z(t)}function Ze(e){const t=I(e.taskId);return t&&Xe(t)||Z(e.taskStatus)?!0:!!e.success}async function ee(){Se.value=await Cs()}async function F(){J.value=await Es()}async function q(){const e=await Is();D.value=e.items||[]}async function xt(){try{const e=await Ds();if(Te.value)return;const t=(e.country_codes||[]).filter(s=>ye.some(a=>a.code===s));t.length&&(g.value=t)}catch{}}async function de(){await Promise.allSettled([q(),F()])}function et(){H&&C.clearTimer("preference-save",H),H=C.setTimeout("preference-save",()=>{H=null,At()},450)}async function At(){if(g.value.length){be.value=!0;try{await Us(g.value)}catch(e){p.error(e instanceof Error?e.message:"保存国家配置失败")}finally{be.value=!1}}}function Lt(e){Oe.value=e}async function tt(){const e=ae.value.trim();if(!e){p.warning("请输入店铺名");return}ne.value=!0;try{await $s(e),ae.value="",await ee(),await F()}catch(t){p.error(t instanceof Error?t.message:"添加失败")}finally{ne.value=!1}}async function Ut(e){try{await Ns(e.id),await ee(),await F()}catch(t){p.error(t instanceof Error?t.message:"删除失败")}}function Ft(e){return g.value.includes(e)}function st(e){return g.value.length===1&&g.value[0]===e}function Rt(e,t){const s=t.target;if(s){if(!s.checked&&st(e)){s.checked=!0,p.warning("至少保留 1 个国家");return}Ot(e,s.checked)}}function Ot(e,t){if(Te.value=!0,t)g.value.includes(e)||(g.value=[...g.value,e]);else{if(g.value.length<=1){p.warning("至少保留 1 个国家");return}g.value=g.value.filter(s=>s!==e)}et()}function Vt(e){G.value=e}function Ht(){G.value=null}function Bt(e){const t=G.value;if(G.value=null,t==null||t===e)return;Te.value=!0;const s=[...g.value],[a]=s.splice(t,1);s.splice(e,0,a),g.value=s,et()}function qt(){x.value&&(k.value=Me(k.value,!0)),x.value||(k.value=[])}function zt(){const e=k.value[k.value.length-1],t=e?Et(e,60):$e();k.value=[...k.value,t]}function Kt(e){k.value.length<=1||(k.value=k.value.filter((t,s)=>s!==e))}function jt(e,t){const s=[...k.value];s[e]=t||"",k.value=Me(s,!1)}function Gt(e,t){const s=new Map;for(const a of e)s.set(L(a),a);for(const a of t)s.set(L(a),a);return Array.from(s.values())}async function Jt(){const e=Oe.value.map(t=>t.shop_name).filter(Boolean);if(!e.length){p.warning("请先选择候选店铺");return}oe.value=!0;try{const t=await Ms(e);T.value=Gt(T.value,t.items||[]),Ne(),_e.value&&gt(),p.success(`本次返回 ${t.items?.length||0} 条匹配结果`)}catch(t){p.error(t instanceof Error?t.message:"匹配失败")}finally{oe.value=!1}}function Yt(e){T.value=T.value.filter(t=>L(t)!==L(e)),Ne()}function R(e){const t=new Set(e.map(s=>L(s)));T.value=T.value.filter(s=>!t.has(L(s))),Ne()}function Qt(){if(!x.value)return;const e=Date.now(),t=k.value.map(n=>n.trim()).filter(Boolean);if(!t.length)throw new Error("请至少选择一个执行时间");const s=t.map(n=>{const u=W(n);if(!u)throw new Error(`时间格式无效: ${n}`);return{raw:Ct(u),picker:re(u),time:u.getTime()}}).sort((n,u)=>n.time-u.time);for(let n=1;n<s.length;n+=1)if(s[n].time===s[n-1].time)throw new Error("执行时间不能重复");const a=s.filter(n=>n.time>e);if(!a.length)throw new Error("执行时间必须晚于当前时间,请重新选择");return a.length!==s.length&&(k.value=a.map(n=>n.picker),p.warning("已自动移除早于当前时间的执行时间")),a.map(n=>n.raw)}function Me(e,t){const s=Date.now(),a=e.map(r=>r.trim()).filter(Boolean).map(r=>{const f=W(r);return f?{value:re(f),time:f.getTime()}:null}).filter(r=>!!r).filter(r=>r.time>s).sort((r,f)=>r.time-f.time),n=[],u=new Set;for(const r of a)u.has(r.value)||(u.add(r.value),n.push(r.value));return!n.length&&t?[$e()]:n}function Wt(e){return e.skipAsinsByCountry||e.skip_asins_by_country||{}}function Xt(e){return e.skipAsinDetailsByCountry||e.skip_asin_details_by_country||{}}function at(e,t,s,a,n=!0){const u=Wt(t),r=Xt(t);return{type:"shop-match-run",ts:Date.now(),data:{taskId:e,user_id:Tt(),items:[{shopName:t.shopName,shopId:t.shopId,platform:t.platform,companyName:t.companyName,matched:!0,matchStatus:t.matchStatus,matchMessage:t.matchMessage,skip_asins_by_country:u,skipAsinsByCountry:u,skip_asin_details_by_country:r,skipAsinDetailsByCountry:r}],country_codes:[...s],skip_asins_by_country:u,skipAsinsByCountry:u,skip_asin_details_by_country:r,skipAsinDetailsByCountry:r,risk_listing_filter:ke.value,stage_index:a,final_stage:n}}}function Pe(e){const t=d.value[e]?.task,s=t?.scheduleStages||[],a=t?.currentStageIndex;if(typeof a!="number")return null;const n=s.find(u=>u.stageIndex===a);return n?.scheduledAt?{stageIndex:a,scheduledAt:n.scheduledAt,finalStage:a===s.length-1}:null}async function Zt(e,t){const s=Fe();if(!s?.enqueue_json)throw new Error("当前客户端未提供 enqueue_json");const a=Pe(e),n=d.value[e],u=n?.task?.countryCodes||g.value;if(!a)throw new Error(`任务 ${e} 缺少待执行阶段`);ie(e),await lt(()=>Fs(e,a.stageIndex),(o,h)=>{S.value=`任务 ${e} 等待后端恢复后再激活执行(${o}/${h}...`}),w.value={...w.value,[e]:"RUNNING"},n?.task&&(d.value={...d.value,[e]:{...n,task:{...n.task,status:"RUNNING",activeStageIndex:a.stageIndex}}}),B(),U();const r=at(e,t,u,a.stageIndex,a.finalStage);j.value=JSON.stringify(r,null,2);const f=await s.enqueue_json(r);if(!f?.success)throw new Error(f?.error||`任务 ${e} 推送失败`);Qe(e),S.value=`任务 ${e} 已推送第 ${a.stageIndex+1}`,se(!0)}function nt(e){const t=W(e);return t?t.getTime():Number.NaN}function es(){const e=new Set(y.value);for(const s of Object.keys(d.value)){const a=I(s);a>0&&e.add(a)}for(const s of D.value){const a=I(s.taskId);a>0&&e.add(a)}const t=Array.from(e).map(s=>{const a=d.value[s],n=w.value[s]||a?.task?.status,u=a?.items?.[0]||D.value.find(o=>I(o.taskId)===s),r=Pe(s);if(n!=="SCHEDULED"||!u||!r?.scheduledAt)return null;const f=nt(r.scheduledAt);return!Number.isFinite(f)||f>Date.now()?null:{taskId:s,item:u,scheduledTime:f}}).filter(s=>!!s);return t.sort((s,a)=>s.scheduledTime-a.scheduledTime||s.taskId-a.taskId),t}async function xe(){if(Ee.value)return;const e=es();if(e.length){Ee.value=!0;try{const t=e[0];try{await Zt(t.taskId,t.item),await ls(t.taskId)}catch(s){const a=s instanceof Error?s.message:`任务 ${t.taskId} 调度失败`,n=`${t.taskId}:${a}`,u=Date.now();S.value=a,(He!==n||u-Ve>1e4)&&(He=n,Ve=u,p.error(a)),await Promise.allSettled([q(),rt()])}}finally{Ee.value=!1,$()}}}function ts(e,t){if(_||!t)return;ie(e);const s=nt(t);if(!Number.isFinite(s))return;const a=Math.max(0,s-Date.now()),n=C.setTimeout("scheduled-dispatch",()=>{N.delete(e),N.size||fe(),_||xe()},a);N.set(e,n),ot()}function $(){if(_)return;const e=new Set(y.value);for(const t of Object.keys(d.value)){const s=I(t);s>0&&e.add(s)}for(const t of D.value){const s=I(t.taskId);s>0&&e.add(s)}for(const t of e){const a=d.value[t]?.task?.status||w.value[t],n=Pe(t);a==="SCHEDULED"&&n?.scheduledAt?ts(t,n.scheduledAt):ie(t)}N.size?ot():fe(),xe()}function ot(){_||Y||!N.size||(Y=C.setInterval("schedule-heartbeat",()=>{_||xe()},3e4))}function fe(){Y&&(C.clearTimer("schedule-heartbeat",Y),Y=null)}function he(){$(),y.value.length&&se(!0)}const ss=["无法连接到后端服务","bad gateway","gateway timeout","network error","timeout","502","503","504"];function te(e){return _?Promise.resolve():C.sleep("queue-wait",e)}function as(){C.clearCategory("queue-wait")}function Ae(e){const t=(e instanceof Error?e.message:String(e||"")).toLowerCase();return ss.some(s=>t.includes(s.toLowerCase()))}async function lt(e,t,s=10){let a=0;for(;;){if(_)throw new Error("component disposed");try{return await e()}catch(n){if(a+=1,!Ae(n)||a>=s)throw n;t(a,s),await te(O())}}}async function rt(){if(!y.value.length)return{settledTaskIds:[]};try{const e=await Re(y.value),t={...d.value},s=new Set;for(const a of e.missingTaskIds||[])X(a),delete t[a],s.add(a);for(const a of e.items||[]){const n=a.task?.id;if(!n)continue;const u=t[n];t[n]=u?{...u,task:{...u.task||{},...a.task||{}}}:a;const r=a.task?.status||"";if(r){if(w.value[n]=r,Z(r)){ce(n),s.add(n);continue}r==="SCHEDULED"&&(We(n),s.add(n))}}return d.value=t,B(),U(),$(),{settledTaskIds:Array.from(s)}}catch{return{settledTaskIds:[]}}}function O(){return Rs()}function ut(e=!1){if(_)return;if(M.value){if(!e)return;C.clearTimer("task-poll",M.value),M.value=null}const t=async()=>{if(M.value=null,!_){if(Ce.value||!y.value.length){y.value.length&&ut();return}Ce.value=!0;try{const{settledTaskIds:s}=await rt();s.length&&await Promise.allSettled([q(),F()])}finally{Ce.value=!1}!_&&y.value.length&&(M.value=C.setTimeout("task-poll",t,O()))}};e?t():M.value=C.setTimeout("task-poll",t,O())}function se(e=!1){ut(e)}function ns(){M.value&&(C.clearTimer("task-poll",M.value),M.value=null)}async function os(e){let t=0;const s=30;for(;;){if(_)return"STOPPED";try{const a=await Re([e]);if(t>0&&(S.value=`任务 ${e} 后端已恢复,继续等待执行结果...`),t=0,(a.missingTaskIds||[]).includes(e))return X(e),await de(),$(),"FAILED";const n=(a.items||[]).find(r=>r.task?.id===e),u=n?.task?.status||"";if(n){const r=d.value[e];d.value={...d.value,[e]:r?{...r,task:{...r.task||{},...n.task||{}}}:n},B()}if(u&&(w.value[e]=u,U()),Z(u))return ce(e),await de(),$(),u}catch(a){if(!Ae(a))throw a;if(t+=1,t>=s)throw new Error(`任务 ${e} 等待后端恢复超时,请稍后手动刷新查看状态`);S.value=`任务 ${e} 运行中,正在等待后端服务恢复(${t}/${s}...`,(t===1||t%5===0)&&p.warning(`任务 ${e} 运行中,后端服务暂时不可用,正在自动重试`),await te(O());continue}await te(O())}}async function ls(e){let t=0;const s=30;for(;;){if(_)return"STOPPED";try{const a=await Re([e]);if(t>0&&(S.value=`任务 ${e} 后端已恢复,继续等待当前轮次结束...`),t=0,(a.missingTaskIds||[]).includes(e))return X(e),await de(),$(),"FAILED";const n=(a.items||[]).find(r=>r.task?.id===e),u=n?.task?.status||"";if(n){const r=d.value[e];d.value={...d.value,[e]:r?{...r,task:{...r.task||{},...n.task||{}}}:n},B()}if(u&&(w.value[e]=u,U()),!u||u==="RUNNING"){await te(O());continue}return Z(u)?(ce(e),await de(),$(),u):(u==="SCHEDULED"&&(We(e),$()),u)}catch(a){if(!Ae(a))throw a;if(t+=1,t>=s)throw new Error(`任务 ${e} 等待当前轮次结束超时,请稍后手动刷新查看状态`);S.value=`任务 ${e} 运行中,正在等待当前轮次结束(${t}/${s}...`,(t===1||t%5===0)&&p.warning(`任务 ${e} 运行中,后端服务暂时不可用,正在自动重试`),await te(O())}}}function Le(e){const t=I(e.taskId);return t?w.value[t]||d.value[t]?.task?.status||e.taskStatus||"":e.taskStatus||""}function it(e){const t=I(e.taskId);return t?d.value[t]:void 0}function ct(e){const s=it(e)?.task,a=s?.scheduleStages||[];if(!a.length)return"";const n=a.length,u=typeof s?.activeStageIndex=="number"?s.activeStageIndex:void 0,r=typeof s?.currentStageIndex=="number"?s.currentStageIndex:void 0;return typeof u=="number"?`执行进度: 第 ${u+1}/${n} 次执行中`:typeof r=="number"?`执行进度: 等待第 ${r+1}/${n}`:`执行进度: 共 ${n}`}function dt(e){const s=it(e)?.task,a=s?.scheduleStages||[];if(typeof s?.currentStageIndex=="number"){const n=a.find(u=>u.stageIndex===s.currentStageIndex);if(n?.scheduledAt)return Je(n.scheduledAt)}return e.scheduledAt?Je(e.scheduledAt):""}function ft(e){const t=Le(e);return t==="SCHEDULED"?"待执行":t==="RUNNING"?"执行中":t==="SUCCESS"||t==="COMPLETED"?"已完成":t==="FAILED"?"失败":e.success?"已完成":"未知"}function ht(e){const t=Le(e);return t==="SUCCESS"||t==="COMPLETED"?"success":t==="FAILED"?"failed":"running"}function vt(e){const t=Le(e);return!!e.resultId&&(!!e.fileReady||!!e.downloadUrl)&&(t==="SUCCESS"||t==="COMPLETED")}async function pt(e){if(!e.resultId)return;const t=Fe();if(!t?.save_file_from_url_new){p.error("当前客户端未提供下载能力");return}const s=Ps(e.resultId),a=e.outputFilename||`${e.shopName||"result"}.xlsx`,n=await t.save_file_from_url_new(s,a);n.success?p.success(`已保存: ${n.path||a}`):n.error&&n.error!=="用户取消"&&p.error(n.error)}async function mt(e){const t=I(e.taskId),s=Number(e.resultId||0);try{if(t>0)await xs(t),X(t);else if(s>0)await As(s),D.value=D.value.filter(a=>Number(a.resultId||0)!==s),R([e]);else throw new Error("缺少可删除的任务标识");await Promise.allSettled([q(),ee(),F()]),p.success("删除成功")}catch(a){if(Mt(a)){t>0?X(t):s>0&&(D.value=D.value.filter(n=>Number(n.resultId||0)!==s)),R([e]),await Promise.allSettled([q(),ee(),F()]),p.success("后端记录已不存在,本地记录已同步清理");return}p.error(a instanceof Error?a.message:"删除失败")}}function rs(e){const t=(e||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[t]||t||"—"}function us(e){const t=(e.matchMessage||"").trim();return t||(e.matched&&e.matchStatus==="MATCHED"?"紫鸟索引已命中,可推送队列":e.matched?"已关联索引,请结合状态列查看是否可推送":"未命中或未就绪,请检查店铺名与索引刷新")}async function is(){_e.value=!0,await gt()}function cs(){return T.value.find(e=>e.matched)}async function gt(){if(_||we.value)return;const e=Fe();if(!e?.enqueue_json){p.error("当前客户端未提供 enqueue_json");return}if(!T.value.filter(r=>r.matched).length){p.warning("请先匹配可用店铺");return}if(!g.value.length){p.warning("请至少勾选一个国家");return}let s;try{s=Qt()}catch(r){p.error(r instanceof Error?r.message:"定时配置无效");return}we.value=!0,P.value=!0,j.value="";let a=0,n=0,u=0;try{for(;!_&&_e.value;){const r=cs();if(!r)break;u+=1;try{const f=await lt(()=>Ls([r],g.value,s),(Ue,ve)=>{S.value=`后端服务暂时不可用,正在重试创建任务(${Ue}/${ve}...`}),o=f.taskId,h=s?.length?"SCHEDULED":"RUNNING",z={task:{id:o,status:h,scheduledAt:s?.[0],countryCodes:[...g.value],currentStageIndex:s?.length?0:void 0,activeStageIndex:void 0,scheduleStages:(s||[]).map((Ue,ve)=>({stageIndex:ve,scheduledAt:Ue,status:ve===0?"SCHEDULED":"PENDING"}))},items:f.items};if(d.value={...d.value,[o]:z},w.value={...w.value,[o]:h},B(),U(),!f.items?.[0]){R([r]);continue}if(s?.length){a+=1,$(),S.value=`任务 ${o} 已创建,共 ${s.length} 个执行时间点`,R([r]);continue}const yt=at(o,r,g.value);j.value=JSON.stringify(yt,null,2);const St=await e.enqueue_json(yt);if(!St?.success){n+=1,S.value=`任务 ${o} 推送失败,已自动继续下一条:${St?.error||"未知错误"}`,p.error(S.value),R([r]);continue}if(Qe(o),se(!0),R([r]),S.value=`任务 ${o} 已入队,等待执行完成`,await os(o)!=="SUCCESS"){n+=1,S.value=`任务 ${o} 执行失败,已自动继续下一条`,p.error(S.value);continue}a+=1,S.value=`任务 ${o} 已完成`}catch(f){if(_)break;n+=1,S.value=`${u} 条任务处理失败,已自动继续下一条:${f instanceof Error?f.message:"未知错误"}`,p.error(S.value),R([r]);continue}}$(),s?.length||se(!0),!_&&(a>0||n>0)&&p.success(s?.length?`定时任务已创建:成功 ${a} 条,失败 ${n}`:`店铺推送已完成:成功 ${a} 条,失败 ${n}`)}catch(r){if(_)return;const f=r instanceof Error?r.message:"推送失败";S.value=f,p.error(f)}finally{we.value=!1,P.value=!1}}return fs(async()=>{It(),Dt(),$t(),Nt(),k.value=Me(k.value,x.value),Pt(),await Promise.allSettled([ee(),xt(),q(),F()]),window.addEventListener("focus",he),document.addEventListener("visibilitychange",he),$(),y.value.length&&se(!0)}),hs(()=>{_=!0,ns(),fe(),as(),window.removeEventListener("focus",he),document.removeEventListener("visibilitychange",he),H&&C.clearTimer("preference-save",H);for(const e of N.values())C.clearTimer("scheduled-dispatch",e);N.clear(),C.clearScope()}),(e,t)=>{const s=ms,a=gs,n=ys,u=ks,r=ws,f=Ts;return i(),c("div",js,[b(vs,{active:"shop-match"}),l("div",Gs,[l("aside",Js,[t[10]||(t[10]=l("div",{class:"section-title"},"店铺候选",-1)),l("div",Ys,[t[4]||(t[4]=l("div",{class:"hint"},"输入店铺名后点“添加”加入下方备选区。勾选备选店铺后先做“匹配店铺”,确认命中紫鸟索引后再推送到 Python 队列。",-1)),l("div",Qs,[b(s,{modelValue:ae.value,"onUpdate:modelValue":t[0]||(t[0]=o=>ae.value=o),clearable:"",placeholder:"请输入店铺名后回车或点击添加",onKeyup:ps(tt,["enter"])},null,8,["modelValue"]),l("button",{type:"button",class:"opt-btn",disabled:ne.value,onClick:tt},v(ne.value?"添加中...":"添加"),9,Ws)])]),t[11]||(t[11]=l("div",{class:"section-title"},"备选店铺",-1)),Se.value.length?(i(),c("div",Zs,[b(n,{data:Se.value,"row-key":"id",height:"240",class:"candidate-table",onSelectionChange:Lt},{default:A(()=>[b(a,{type:"selection",width:"42"}),b(a,{prop:"shop_name",label:"店铺名","min-width":"120","show-overflow-tooltip":""}),b(a,{label:"操作",width:"72",align:"center"},{default:A(({row:o})=>[l("button",{type:"button",class:"link-danger",onClick:h=>Ut(o)},"删除",8,ea)]),_:1})]),_:1},8,["data"])])):(i(),c("div",Xs,"暂无备选店铺,请先输入并添加")),t[12]||(t[12]=l("div",{class:"section-title"},"国家配置",-1)),t[13]||(t[13]=l("p",{class:"hint country-pref-hint"},"勾选的国家会在每一个执行时间点都执行一遍。勾选区会按照已选顺序排在前面,下方支持拖拽排序,和商品风险页保持一致。",-1)),l("div",ta,[(i(!0),c(V,null,K(bt.value,o=>(i(),c("label",{key:o.code,class:"country-check-row"},[l("input",{type:"checkbox",class:"country-check-input",checked:Ft(o.code),disabled:st(o.code),onChange:h=>Rt(o.code,h)},null,40,sa),l("span",aa,v(o.label)+" ("+v(o.code)+")",1)]))),128))]),g.value.length?(i(),c("div",na,[t[6]||(t[6]=l("div",{class:"country-order-caption"},"已选顺序(拖拽 ⋮⋮ 调整)",-1)),l("div",oa,[(i(!0),c(V,null,K(g.value,(o,h)=>(i(),c("div",{key:o,class:pe(["country-drag-row",{dragging:G.value===h}]),draggable:"true",onDragstart:z=>Vt(h),onDragend:Ht,onDragover:t[1]||(t[1]=kt(()=>{},["prevent"])),onDrop:kt(z=>Bt(h),["prevent"])},[t[5]||(t[5]=l("span",{class:"drag-handle",title:"拖动排序"},"⋮⋮",-1)),l("span",ra,v(Ge(o))+" ("+v(o)+")",1)],42,la))),128))])])):E("",!0),be.value?(i(),c("div",ua,"保存中...")):E("",!0),t[14]||(t[14]=l("div",{class:"section-title"},"商品列表筛选",-1)),t[15]||(t[15]=l("p",{class:"hint listing-filter-hint"},"与“推送到 Python 队列”一并下发,供 Python 区分处理场景。",-1)),l("div",ia,[b(r,{modelValue:ke.value,"onUpdate:modelValue":t[2]||(t[2]=o=>ke.value=o),class:"listing-filter-select",teleported:"",placeholder:"选择筛选类型"},{default:A(()=>[(i(!0),c(V,null,K(Ss(zs),o=>(i(),wt(u,{key:o.value,label:o.label,value:o.value},null,8,["label","value"]))),128))]),_:1},8,["modelValue"])]),t[16]||(t[16]=l("div",{class:"section-title"},"定时执行",-1)),l("label",ca,[_s(l("input",{"onUpdate:modelValue":t[3]||(t[3]=o=>x.value=o),type:"checkbox",disabled:P.value,onChange:qt},null,40,da),[[bs,x.value]]),t[7]||(t[7]=l("span",null,"启用多时间点调度",-1))]),x.value?(i(),c("div",fa,[(i(!0),c(V,null,K(k.value,(o,h)=>(i(),c("div",{key:`schedule-${h}`,class:"schedule-row"},[b(f,{"model-value":o,type:"datetime","value-format":"YYYY-MM-DD HH:mm:ss",format:"MM-DD HH:mm",placeholder:"选择执行时间",disabled:P.value,class:"schedule-picker","onUpdate:modelValue":z=>jt(h,z)},null,8,["model-value","disabled","onUpdate:modelValue"]),l("button",{type:"button",class:"schedule-remove",disabled:P.value||k.value.length<=1,onClick:z=>Kt(h)},"删除",8,ha)]))),128)),l("button",{type:"button",class:"schedule-add",disabled:P.value,onClick:zt},"添加时间点",8,va),t[8]||(t[8]=l("p",{class:"hint schedule-hint"},"默认开启定时;支持按 `MM-DD HH:mm` 配置多个时间点,前端不再限制选择更早时间,实际是否可执行以后端校验为准。",-1))])):E("",!0),l("div",pa,[l("button",{type:"button",class:"btn-run",disabled:oe.value,onClick:Jt},v(oe.value?"匹配中...":"匹配店铺"),9,ma),l("button",{type:"button",class:"btn-run btn-queue",disabled:P.value||!T.value.length,onClick:is},v(P.value?"推送中...":x.value?"创建定时任务":"推送到 Python 队列"),9,ga)]),t[17]||(t[17]=l("p",{class:"loading-msg"},[me("已支持多阶段定时执行Python 每处理完一店可回传 "),l("code",null,"/api/shop-match/tasks/{taskId}/result"),me(",后端会按阶段汇总并在超时场景自动收尾。")],-1)),S.value?(i(),c("div",ya,[t[9]||(t[9]=l("div",{class:"section-title queue-debug-title"},"推送结果",-1)),l("div",Sa,v(S.value),1),j.value?(i(),c("pre",ka,v(j.value),1)):E("",!0)])):E("",!0)]),l("section",wa,[t[26]||(t[26]=l("div",{class:"panel-header"},"匹配与任务",-1)),l("div",_a,[l("div",ba,[l("div",Ta,[t[18]||(t[18]=l("span",{class:"summary-label"},"候选店铺",-1)),l("strong",null,v(J.value.candidateCount),1)]),l("div",Ca,[t[19]||(t[19]=l("span",{class:"summary-label"},"已结束任务",-1)),l("strong",null,v(J.value.processedTaskCount),1)]),l("div",Ea,[t[20]||(t[20]=l("span",{class:"summary-label"},"成功",-1)),l("strong",null,v(J.value.successTaskCount),1)]),l("div",Ia,[t[21]||(t[21]=l("span",{class:"summary-label"},"失败",-1)),l("strong",null,v(J.value.failedTaskCount),1)])]),t[25]||(t[25]=l("div",{class:"subsection-title"},"匹配结果",-1)),T.value.length?(i(),wt(n,{key:1,data:T.value,"row-key":L,"highlight-current-row":!1,class:"result-table match-table"},{default:A(()=>[b(a,{prop:"shopName",label:"店铺名","min-width":"100"}),b(a,{label:"匹配",width:"72",align:"center"},{default:A(({row:o})=>[l("span",{class:pe(o.matched?"ok":"fail")},v(o.matched?"是":"否"),3)]),_:1}),b(a,{prop:"shopId",label:"店铺ID","min-width":"120","show-overflow-tooltip":""}),b(a,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),b(a,{prop:"companyName",label:"公司","min-width":"100","show-overflow-tooltip":""}),b(a,{label:"状态",width:"100","show-overflow-tooltip":""},{default:A(({row:o})=>[me(v(rs(o.matchStatus)),1)]),_:1}),b(a,{label:"说明","min-width":"140","show-overflow-tooltip":""},{default:A(({row:o})=>[me(v(us(o)),1)]),_:1}),b(a,{label:"操作",width:"72",align:"center"},{default:A(({row:o})=>[l("button",{type:"button",class:"link-danger",onClick:h=>Yt(o)},"删除",8,$a)]),_:1})]),_:1},8,["data"])):(i(),c("div",Da,"完成“匹配店铺”后,在此展示紫鸟索引匹配结果,供核对后再推送队列。")),l("div",Na,[t[24]||(t[24]=l("div",{class:"result-list-header"},[l("span",null,"处理记录")],-1)),_t.value?(i(),c(V,{key:1},[Ie.value.length?(i(),c("div",Pa,[t[22]||(t[22]=l("div",{class:"result-subsection-title"},"当前任务",-1)),l("ul",xa,[(i(!0),c(V,null,K(Ie.value,o=>(i(),c("li",{key:`cur-${o.resultId}-${o.taskId}`,class:"task-item"},[l("div",Aa,[l("span",{class:"id",title:o.shopName||""},v(o.shopName||"-"),9,La),l("div",Ua,"任务 ID: "+v(o.taskId??"-"),1),o.platform?(i(),c("div",Fa,"平台: "+v(o.platform),1)):E("",!0),ct(o)?(i(),c("div",Ra,v(ct(o)),1)):E("",!0),dt(o)?(i(),c("div",Oa,"下一次: "+v(dt(o)),1)):E("",!0),o.error?(i(),c("div",Va,"错误: "+v(o.error),1)):E("",!0)]),l("div",Ha,[l("span",{class:pe(["status",ht(o)])},v(ft(o)),3),vt(o)?(i(),c("button",{key:0,type:"button",class:"download",onClick:h=>pt(o)},"下载",8,Ba)):E("",!0),l("button",{type:"button",class:"btn-delete",onClick:h=>mt(o)},"删除",8,qa)])]))),128))])])):E("",!0),De.value.length?(i(),c("div",za,[t[23]||(t[23]=l("div",{class:"result-subsection-title"},"历史任务",-1)),l("ul",Ka,[(i(!0),c(V,null,K(De.value,o=>(i(),c("li",{key:`his-${o.resultId}-${o.taskId}`,class:"task-item"},[l("div",ja,[l("span",{class:"id",title:o.shopName||""},v(o.shopName||"-"),9,Ga),l("div",Ja,"任务 ID: "+v(o.taskId??"-"),1),o.outputFilename?(i(),c("div",Ya,"文件: "+v(o.outputFilename),1)):E("",!0),o.error?(i(),c("div",Qa,"错误: "+v(o.error),1)):E("",!0)]),l("div",Wa,[l("span",{class:pe(["status",ht(o)])},v(ft(o)),3),vt(o)?(i(),c("button",{key:0,type:"button",class:"download",onClick:h=>pt(o)},"下载",8,Xa)):E("",!0),l("button",{type:"button",class:"btn-delete",onClick:h=>mt(o)},"删除",8,Za)])]))),128))])])):E("",!0)],64)):(i(),c("div",Ma,"暂无处理记录。推送队列并等待 Python 回传后,将在此显示下载链接。"))])])])])])}}}),tn=Os(en,[["__scopeId","data-v-288e061c"]]);Vs.locale("zh-cn");Hs(tn).use(Bs,{locale:qs}).mount("#app");