modified: amazon/price_match.py modified: assets/appearance-patent.js modified: assets/delete-brand.js modified: assets/patrol-delete.js modified: assets/price-track.js modified: assets/product-risk.js modified: assets/query-asin.js modified: assets/shop-match.js modified: new_web_source/delete-brand.html
2 lines
18 KiB
JavaScript
2 lines
18 KiB
JavaScript
import{d as Je,o as je,L as We,a as u,c as i,b as p,B as Xe,e as n,a5 as Ye,a6 as Ge,t as l,V as I,W as Ze,X as et,f as m,U as tt,n as te,x as _e,F as se,r as we,g as v,h as H,a_ as st,a$ as at,b0 as nt,E as c,b1 as ot,b2 as lt,b3 as rt,i as ge,b4 as ut,b5 as it,b6 as ct,b7 as dt,b8 as ft,T as x,b9 as ht,_ as vt,aE as pt,q as mt,s as yt}from"./pywebview-C66x_2Dh.js";import{z as _t}from"./zh-cn-CuE9Zzgz.js";/* empty css *//* empty css */import{c as wt}from"./categorized-timers-JPA-olTr.js";const gt={class:"page-shell module-page"},kt={class:"main-content"},bt={class:"left-panel"},It={class:"input-zone"},St={class:"input-row"},Tt=["disabled"],Ct={key:0,class:"empty-candidates"},Et={key:1,class:"candidate-table-scroll"},$t=["onClick"],Dt={class:"run-row"},Nt=["disabled"],Pt=["disabled"],Mt={key:2,class:"queue-debug-card"},Rt={class:"queue-debug-line"},At={key:0,class:"queue-debug-payload"},qt={class:"right-panel"},Qt={class:"task-list-wrap"},Lt={class:"clean-result-summary"},Bt={class:"summary-card"},Ft={class:"summary-card"},Ot={class:"summary-card"},Ut={class:"summary-card"},Ht={key:0,class:"empty-tasks narrow"},xt=["onClick"],Vt={class:"result-list-wrap"},zt={key:0,class:"empty-tasks"},Kt={key:0,class:"result-subsection"},Jt={class:"task-list"},jt={class:"left split-result-main"},Wt=["title"],Xt={class:"files"},Yt={key:0,class:"files"},Gt={key:1,class:"files"},Zt={key:2,class:"files"},es={class:"files"},ts={class:"files"},ss={key:3,class:"files"},as={class:"task-right"},ns=["onClick"],os={key:1,class:"result-subsection"},ls={class:"task-list"},rs={class:"left split-result-main"},us=["title"],is={class:"files"},cs={key:0,class:"files"},ds={key:1,class:"files"},fs={key:2,class:"files"},hs={class:"files"},vs={key:3,class:"files"},ps={class:"files"},ms={key:4,class:"files"},ys={class:"task-right"},_s=["onClick"],ws=["onClick"],ke=30,gs=Je({__name:"BrandPatrolDeleteTab",setup(bs){const ae=["德国","英国","法国","意大利","西班牙"],M=v(""),V=v([]),R=v([]),y=v([]),k=v([]),E=v({candidateCount:0,processedTaskCount:0,successTaskCount:0,failedTaskCount:0}),A=v(!1),q=v(!1),Q=v(!1),_=v(""),z=v(""),f=v([]),h=v(null),$=v(null),L=v(!1),K=v(!1);let S=null;const T=wt("patrol-delete"),J=H(()=>y.value.filter(e=>e.matched)),B=H(()=>k.value.filter(e=>!ce(e.taskStatus))),j=H(()=>k.value.filter(e=>ce(e.taskStatus))),D=H(()=>L.value||!!h.value||f.value.length>0);function W(){return typeof window<"u"&&window.localStorage.getItem("uid")||"0"}function ne(){return`patrol-delete:matched:${W()}`}function oe(){return`patrol-delete:queue-state:${W()}`}function g(e){return`${(e.shopName||"").trim()}::${e.shopId||""}`}function F(e){return`${e.taskId??0}:${e.resultId??0}`}let w=!1;function le(e){return w?Promise.resolve():T.sleep("queue-wait",e)}function be(){T.clearCategory("queue-wait")}function re(e){const t=e instanceof Error?e.message.toLowerCase():String(e||"").toLowerCase();return t.includes("network error")||t.includes("failed to fetch")||t.includes("timeout")||t.includes("503")||t.includes("502")||t.includes("504")||t.includes("500")||t.includes("load failed")}async function Ie(e,t,o=20){let a=0;for(;;){if(w)throw new Error("component disposed");try{return await e()}catch(r){if(!re(r)||a>=o-1)throw r;a+=1,t?.(a,o),await le(x())}}}function Se(e,t){return`patrol-delete:${e}:${t||"shop"}:${Date.now()}`}function X(e){if(!e)return"-";const t=new Date(e);if(Number.isNaN(t.getTime()))return e;const o=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),r=String(t.getDate()).padStart(2,"0"),s=String(t.getHours()).padStart(2,"0"),d=String(t.getMinutes()).padStart(2,"0"),b=String(t.getSeconds()).padStart(2,"0");return`${o}-${a}-${r} ${s}:${d}:${b}`}function Te(e){const t=(e||"").trim();return{MATCHED:"已匹配",PENDING:"待匹配",CONFLICT:"需人工确认",INDEX_STALE:"索引过期"}[t]||t||"-"}function Ce(e){const t=(e.matchMessage||"").trim();return t||(e.matched&&e.matchStatus==="MATCHED"?"索引已命中,可推送到 Python 队列":e.matched?"已命中索引,请结合状态列确认":"未命中或未就绪,请检查店铺名")}function Ee(){return ae.map(e=>({country:e,rows:[{status:"全部",quantity:"",deleteQuantity:"",processStatus:""}]}))}function $e(){return ae.map(e=>({country:e,ratio:""}))}function ue(e){const t=e.countrySections||[],o=e.cartRatios||[],a=Math.max(...t.map(r=>r.rows.length),1);return Array.from({length:a},(r,s)=>({shopName:s===0?e.shopName:"",countries:t.map(d=>{const b=d.rows[s];return{country:d.country,status:b?.status||"",quantity:b?.quantity||"",deleteQuantity:b?.deleteQuantity||"",processStatus:b?.processStatus||""}}),cartRatios:s===0?o.map(d=>({country:d.country,ratio:d.ratio})):[]}))}function ie(e){return`${ue(e).length} 行状态数据,首行含 ${e.cartRatios?.length||0} 个购物车比例列`}function ce(e){return e==="SUCCESS"||e==="FAILED"||e==="COMPLETED"}function de(e){return e==="SUCCESS"||e==="COMPLETED"?"已完成":e==="FAILED"?"失败":"执行中"}function fe(e){return e==="SUCCESS"||e==="COMPLETED"?"success":e==="FAILED"?"failed":"running"}function De(e){return!!(e.resultId&&(e.fileReady||e.downloadUrl))}function Y(){typeof window>"u"||window.localStorage.setItem(ne(),JSON.stringify(y.value))}function Ne(){try{const e=typeof window<"u"?window.localStorage.getItem(ne()):null;y.value=e?JSON.parse(e):[]}catch{y.value=[]}}function C(){if(typeof window>"u")return;const e={pendingQueue:f.value,activeTaskId:h.value,activeQueueItem:$.value};window.localStorage.setItem(oe(),JSON.stringify(e))}function Pe(){try{const e=typeof window<"u"?window.localStorage.getItem(oe()):null;if(!e)return;const t=JSON.parse(e);f.value=t.pendingQueue||[],h.value=t.activeTaskId??null,$.value=t.activeQueueItem??null}catch{f.value=[],h.value=null,$.value=null}}function O(){h.value=null,$.value=null,C()}function Me(e){const t=e instanceof Error?e.message:String(e||"");return/记录不存在|任务不存在|不存在|已删除|not\s*found|404/i.test(t)}function he(e){y.value=y.value.filter(t=>g(t)!==g(e)),Y()}function Re(e){k.value=k.value.filter(t=>!(e.resultId!=null&&t.resultId===e.resultId||e.taskId!=null&&t.taskId===e.taskId))}function ve(e,t){const o=new Map;for(const a of e)o.set(g(a),a);for(const a of t)o.set(g(a),a);return Array.from(o.values())}async function N(){V.value=await st()}async function U(){E.value=await at()}async function G(){const e=await nt();k.value=e.items||[]}async function P(){await Promise.all([U(),G()])}function Ae(e){if(!e.length)return;const t=new Map(e.map(a=>[F(a),a])),o=k.value.map(a=>{const r=t.get(F(a));return r?{...a,...r,countrySections:r.countrySections||a.countrySections||[],cartRatios:r.cartRatios||a.cartRatios||[]}:a});for(const a of e){const r=F(a);o.some(s=>F(s)===r)||o.push(a)}k.value=o}async function pe(e){const t=Array.from(new Set((e&&e.length?e:B.value.map(a=>a.taskId??0)).filter(a=>Number.isFinite(a)&&a>0)));if(!t.length)return;const o=await ht(t);Ae(o.items||[]),(o.missingTaskIds||[]).length&&await G()}function qe(){if(Z(),w||!D.value)return;const e=async()=>{S=null,!(w||!D.value)&&(await pe(),!w&&D.value&&(S=T.setTimeout("history-poll",e,x()*2)))};S=T.setTimeout("history-poll",e,x()*2)}function Z(){S&&(T.clearTimer("history-poll",S),S=null)}function Qe(e){R.value=e}async function me(){const e=M.value.trim();if(!e){c.warning("请输入店铺名");return}A.value=!0;try{await ot(e),M.value="",await Promise.all([N(),U()]),c.success("已加入备选区")}catch(t){c.error(t instanceof Error?t.message:"添加失败")}finally{A.value=!1}}async function Le(e){try{await lt(e),R.value=R.value.filter(t=>t.id!==e),await Promise.all([N(),U()]),c.success("已删除")}catch(t){c.error(t instanceof Error?t.message:"删除失败")}}function Be(e,t){const o=new Map;for(const a of e)o.set(g(a),a);for(const a of t)o.set(g(a),a);return Array.from(o.values())}async function Fe(){const e=R.value.map(t=>t.shop_name).filter(Boolean);if(!e.length){c.warning("请先勾选备选区店铺");return}q.value=!0;try{const t=await rt(e);y.value=Be(y.value,t.items||[]),Y(),K.value&&(f.value=ve(f.value,J.value),C(),ee()),c.success(`本次返回 ${t.items?.length||0} 条匹配结果`)}catch(t){c.error(t instanceof Error?t.message:"匹配失败")}finally{q.value=!1}}function Oe(e){if(D.value){c.warning("队列执行中,请等待当前串行任务结束后再调整");return}y.value=y.value.filter(t=>g(t)!==g(e)),Y()}function Ue(e){return{shopName:e.shopName,matched:e.matched,shopId:e.shopId,platform:e.platform,companyName:e.companyName,matchStatus:e.matchStatus,matchMessage:e.matchMessage,countrySections:Ee(),cartRatios:$e()}}function He(e,t){return{type:"patrol-delete-run",ts:Date.now(),data:{taskId:e,user_id:Number(W())||0,source:"frontend-vue-patrol-delete",items:[{shopName:t.shopName,shopId:t.shopId,platform:t.platform,companyName:t.companyName,matched:t.matched,matchStatus:t.matchStatus,matchMessage:t.matchMessage}],template_rows:ue(t),country_sections:t.countrySections||[],cart_ratios:t.cartRatios||[]}}}function xe(e){return k.value.find(t=>t.taskId===e)}async function Ve(e){let t=0;for(;;){if(w)return"STOPPED";try{await pe([e]),t>0&&(_.value=`任务 ${e} 后端已恢复,继续等待执行结果...`),t=0;const a=xe(e)?.taskStatus||"";if(a==="SUCCESS"||a==="FAILED"||a==="COMPLETED")return a}catch(o){if(!re(o))throw o;if(t+=1,t>=ke)throw new Error(`任务 ${e} 等待后端恢复超时,请稍后刷新查看状态`);_.value=`任务 ${e} 执行中,正在等待后端服务恢复(${t}/${ke})...`}await le(x())}}async function ee(){if(!(w||L.value)){L.value=!0,Q.value=!0,qe();try{const e=ge();if(!e?.enqueue_json)throw new Error("当前客户端未提供 enqueue_json");for(;!w&&(h.value||f.value.length);){if(h.value){const d=await Ve(h.value);_.value=f.value.length>0?`任务 ${h.value} ${d==="SUCCESS"?"已完成":"执行失败"},自动继续下一个(剩余 ${f.value.length} 条)`:`任务 ${h.value} ${d==="SUCCESS"?"已完成":"执行失败"}`,O();continue}const t=f.value.shift();if(C(),!t)break;const o=await Ie(()=>ut([Ue(t)]),(d,b)=>{_.value=`后端服务暂时不可用,正在重试创建任务(${d}/${b})...`}),a=o.items?.[0];if(!a?.taskId||!a.resultId)throw new Error("后端未返回有效任务标识");h.value=o.taskId,$.value=t,C(),await P();const r=He(o.taskId,a);z.value=JSON.stringify(r,null,2);const s=await e.enqueue_json(r);if(!s?.success){await it(o.taskId,{shops:[{shopName:a.shopName||t.shopName||"",error:s?.error||`任务 ${o.taskId} 推送失败`,countrySections:a.countrySections||[],cartRatios:a.cartRatios||[],shopDone:!0,submissionId:Se(o.taskId,a.shopName||t.shopName),chunkIndex:1,chunkTotal:1}]}),he(t),await P(),_.value=`任务 ${o.taskId} 推送失败,已自动继续下一个任务`,O();continue}he(t),_.value=f.value.length>0?`任务 ${o.taskId} 已入队,等待完成后自动继续下一个(剩余 ${f.value.length} 条)`:`任务 ${o.taskId} 已入队,等待执行完成`}_.value="串行队列已执行完成",await P(),c.success("巡店删除队列已按顺序执行完成")}catch(e){if(w)return;const t=e instanceof Error?e.message:"队列执行失败";_.value=t,c.error(t),await P()}finally{L.value=!1,Q.value=!1,Z(),C()}}}async function ze(){K.value=!0;const e=J.value;if(!e.length){c.warning("请先匹配可用店铺");return}f.value=ve(f.value,e),C(),_.value=`已加入 ${e.length} 条店铺,开始串行执行`,await ee()}async function Ke(e){if(!e.resultId)return;const t=ge();if(!t?.save_file_from_url_new){c.error("当前客户端未提供下载能力");return}const o=ct(e.resultId),a=e.outputFilename||`${e.shopName||"result"}.xlsx`,r=await t.save_file_from_url_new(o,a);r.success?c.success(`已保存: ${r.path||a}`):r.error&&r.error!=="用户取消"&&c.error(r.error)}async function ye(e){try{if(e.taskId)await dt(e.taskId),h.value===e.taskId&&O();else if(e.resultId)await ft(e.resultId);else throw new Error("缺少可删除的任务标识");await Promise.all([N(),P()]),c.success("已删除")}catch(t){if(Me(t)){e.taskId&&h.value===e.taskId&&O(),Re(e),await N(),c.success("后端记录已不存在,已同步移除本地记录");return}c.error(t instanceof Error?t.message:"删除失败")}}return je(async()=>{Ne(),Pe(),await Promise.all([N(),U(),G()]),(h.value||f.value.length)&&(K.value=!0,_.value=h.value!=null?`检测到未完成队列,继续等待任务 ${h.value} 完成并自动接续后续店铺`:`检测到未完成队列,继续执行剩余 ${f.value.length} 条店铺`,ee())}),We(()=>{w=!0,Z(),be(),T.clearScope()}),(e,t)=>{const o=Ge,a=Ze,r=et;return u(),i("div",gt,[p(Xe,{active:"patrol-delete"}),n("div",kt,[n("aside",bt,[t[3]||(t[3]=n("div",{class:"section-title"},"店铺输入",-1)),n("div",It,[t[1]||(t[1]=n("div",{class:"hint"}," 左侧负责录入店铺并加入备选区,确认命中后推送到 Python 队列。巡店删除按店铺串行执行:上一个任务完成后会自动开始下一个,失败也会继续下一个。 ",-1)),n("div",St,[p(o,{modelValue:M.value,"onUpdate:modelValue":t[0]||(t[0]=s=>M.value=s),clearable:"",placeholder:"请输入店铺名后回车或点击添加",onKeyup:Ye(me,["enter"])},null,8,["modelValue"]),n("button",{type:"button",class:"opt-btn",disabled:A.value,onClick:me},l(A.value?"添加中...":"添加"),9,Tt)])]),t[4]||(t[4]=n("div",{class:"section-title"},"备选区",-1)),V.value.length?(u(),i("div",Et,[p(r,{data:V.value,"row-key":"id",height:"260",class:"candidate-table",onSelectionChange:Qe},{default:I(()=>[p(a,{type:"selection",width:"42"}),p(a,{prop:"shop_name",label:"店铺名","min-width":"140","show-overflow-tooltip":""}),p(a,{label:"操作",width:"72",align:"center"},{default:I(({row:s})=>[n("button",{type:"button",class:"link-danger",onClick:d=>Le(s.id)}," 删除 ",8,$t)]),_:1})]),_:1},8,["data"])])):(u(),i("div",Ct," 暂无备选店铺,请先输入并添加 ")),n("div",Dt,[n("button",{type:"button",class:"btn-run",disabled:q.value||D.value,onClick:Fe},l(q.value?"匹配中...":"匹配店铺"),9,Nt),n("button",{type:"button",class:"btn-run btn-queue",disabled:Q.value||!J.value.length,onClick:ze},l(Q.value?"串行执行中...":"推送到 Python 队列"),9,Pt)]),t[5]||(t[5]=n("p",{class:"loading-msg"}," 当前页面会按店铺串行推送任务,并在任务成功或失败后自动接续下一个任务。服务端临时重启时会自动重试查询状态,恢复后继续后续店铺。 ",-1)),_.value?(u(),i("div",Mt,[t[2]||(t[2]=n("div",{class:"section-title queue-debug-title"},"队列状态",-1)),n("div",Rt,l(_.value),1),z.value?(u(),i("pre",At,l(z.value),1)):m("",!0)])):m("",!0)]),n("section",qt,[t[14]||(t[14]=n("div",{class:"panel-header"},"匹配与任务",-1)),n("div",Qt,[n("div",Lt,[n("div",Bt,[t[6]||(t[6]=n("span",{class:"summary-label"},"备选店铺",-1)),n("strong",null,l(E.value.candidateCount),1)]),n("div",Ft,[t[7]||(t[7]=n("span",{class:"summary-label"},"已处理任务",-1)),n("strong",null,l(E.value.processedTaskCount),1)]),n("div",Ot,[t[8]||(t[8]=n("span",{class:"summary-label"},"成功任务",-1)),n("strong",null,l(E.value.successTaskCount),1)]),n("div",Ut,[t[9]||(t[9]=n("span",{class:"summary-label"},"失败任务",-1)),n("strong",null,l(E.value.failedTaskCount),1)])]),t[13]||(t[13]=n("div",{class:"subsection-title"},"匹配结果",-1)),y.value.length?(u(),tt(r,{key:1,data:y.value,"row-key":g,"highlight-current-row":!1,class:"result-table match-table"},{default:I(()=>[p(a,{prop:"shopName",label:"店铺名","min-width":"120"}),p(a,{label:"匹配",width:"72",align:"center"},{default:I(({row:s})=>[n("span",{class:te(s.matched?"ok":"fail")},l(s.matched?"是":"否"),3)]),_:1}),p(a,{prop:"shopId",label:"店铺 ID","min-width":"120","show-overflow-tooltip":""}),p(a,{prop:"platform",label:"平台",width:"88","show-overflow-tooltip":""}),p(a,{prop:"companyName",label:"公司","min-width":"120","show-overflow-tooltip":""}),p(a,{label:"状态",width:"110","show-overflow-tooltip":""},{default:I(({row:s})=>[_e(l(Te(s.matchStatus)),1)]),_:1}),p(a,{label:"说明","min-width":"180","show-overflow-tooltip":""},{default:I(({row:s})=>[_e(l(Ce(s)),1)]),_:1}),p(a,{label:"操作",width:"72",align:"center"},{default:I(({row:s})=>[n("button",{type:"button",class:"link-danger",onClick:d=>Oe(s)}," 删除 ",8,xt)]),_:1})]),_:1},8,["data"])):(u(),i("div",Ht," 完成“匹配店铺”后,这里会展示匹配结果。 ")),n("div",Vt,[t[12]||(t[12]=n("div",{class:"result-list-header"},[n("span",null,"任务记录")],-1)),!B.value.length&&!j.value.length?(u(),i("div",zt," 暂无任务记录。推送到 Python 队列后,这里会展示当前任务和历史任务。 ")):(u(),i(se,{key:1},[B.value.length?(u(),i("div",Kt,[t[10]||(t[10]=n("div",{class:"result-subsection-title"},"当前任务",-1)),n("ul",Jt,[(u(!0),i(se,null,we(B.value,s=>(u(),i("li",{key:`${s.resultId}-${s.taskId}`,class:"task-item"},[n("div",jt,[n("span",{class:"id",title:s.shopName||""},l(s.shopName||"-"),9,Wt),n("div",Xt,"任务 ID: "+l(s.taskId??"-"),1),s.resultId?(u(),i("div",Yt," 结果 ID: "+l(s.resultId),1)):m("",!0),s.shopId?(u(),i("div",Gt," 店铺 ID: "+l(s.shopId),1)):m("",!0),s.platform?(u(),i("div",Zt," 平台: "+l(s.platform),1)):m("",!0),n("div",es," 创建时间: "+l(X(s.createdAt)),1),n("div",ts," 模板结构: "+l(ie(s)),1),s.error?(u(),i("div",ss," 错误: "+l(s.error),1)):m("",!0)]),n("div",as,[n("span",{class:te(["status",fe(s.taskStatus)])},l(de(s.taskStatus)),3),n("button",{type:"button",class:"btn-delete",onClick:d=>ye(s)}," 删除 ",8,ns)])]))),128))])])):m("",!0),j.value.length?(u(),i("div",os,[t[11]||(t[11]=n("div",{class:"result-subsection-title"},"历史任务",-1)),n("ul",ls,[(u(!0),i(se,null,we(j.value,s=>(u(),i("li",{key:`${s.resultId}-${s.taskId}`,class:"task-item"},[n("div",rs,[n("span",{class:"id",title:s.shopName||""},l(s.shopName||"-"),9,us),n("div",is,"任务 ID: "+l(s.taskId??"-"),1),s.resultId?(u(),i("div",cs," 结果 ID: "+l(s.resultId),1)):m("",!0),s.shopId?(u(),i("div",ds," 店铺 ID: "+l(s.shopId),1)):m("",!0),s.platform?(u(),i("div",fs," 平台: "+l(s.platform),1)):m("",!0),n("div",hs," 创建时间: "+l(X(s.createdAt)),1),s.finishedAt?(u(),i("div",vs," 完成时间: "+l(X(s.finishedAt)),1)):m("",!0),n("div",ps," 模板结构: "+l(ie(s)),1),s.error?(u(),i("div",ms," 错误: "+l(s.error),1)):m("",!0)]),n("div",ys,[n("span",{class:te(["status",fe(s.taskStatus)])},l(de(s.taskStatus)),3),De(s)?(u(),i("button",{key:0,type:"button",class:"archive",onClick:d=>Ke(s)}," 下载结果 ",8,_s)):m("",!0),n("button",{type:"button",class:"btn-delete",onClick:d=>ye(s)}," 删除 ",8,ws)])]))),128))])])):m("",!0)],64))])])])])])}}}),ks=vt(gs,[["__scopeId","data-v-f47847c1"]]);pt.locale("zh-cn");mt(ks).use(yt,{locale:_t}).mount("#app");
|