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

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