import{g as R,k as j,B as G,c as l,a as e,d as p,F as u,r as h,J,l as A,t as d,p as g,m,q as z,s as L,x as v,z as k,y as B,o as i,K as D,n as w,v as H,_ as O}from"./T3_facgV.js";import{u as Q}from"./YYZWHM5Z.js";import{u as W}from"./D7TmXHpa.js";import"./BaPL5gDJ.js";const X={class:"flex items-start justify-between mb-5 flex-wrap gap-3"},Y={key:0,class:"bg-white rounded-xl border border-slate-100 py-16 text-center"},Z={key:1,class:"bg-white rounded-xl border border-slate-100 py-16 text-center text-slate-400"},tt={key:2,class:"app-grid"},et=["onClick","onKeydown"],st={class:"ac-head"},at={class:"ac-logo"},nt={class:"min-w-0 flex-1"},ot={class:"ac-title"},lt={class:"ac-meta"},it={key:0,class:"chip"},dt={class:"ac-remark"},rt={class:"ac-stats"},ct={class:"ac-stat"},pt={class:"ac-stat"},ut={class:"ac-stat"},mt={class:"ac-regions"},vt={key:1,class:"text-xs text-slate-300"},bt=["onClick"],ft=["onClick"],xt=["onClick"],_t={key:0,class:"app-card orphan"},yt={class:"orphan-list"},ht={class:"min-w-0"},gt={class:"text-sm font-medium text-slate-700 truncate"},kt={class:"text-[11px] text-slate-400 font-mono"},wt=["onUpdate:modelValue"],Ct=["value"],$t=["disabled","onClick"],Vt={class:"modal-box max-w-lg"},Ut={class:"font-bold text-lg"},Mt={class:"form-control"},At={class:"form-control"},zt={class:"form-control"},Nt={class:"flex items-center gap-2 cursor-pointer pt-1"},St={class:"modal-action"},Bt=R({__name:"index",setup(Dt){const{consoleApi:r}=Q(),{success:C,error:b}=W(),F=j(),f=v([]),$=v([]),V=v(!1),c=B({}),K=k(()=>{const a=new Map;for(const t of $.value){const s=t.app_name||"";a.has(s)||a.set(s,[]),a.get(s).push(t)}return a}),N=k(()=>f.value.map(a=>{const t=K.value.get(a.name)||[];return{product:a,deployments:t,okCount:t.filter(s=>s.status!=="pending").length,pendingCount:t.filter(s=>s.status==="pending").length}})),U=k(()=>{const a=new Set(f.value.map(t=>t.name));return $.value.filter(t=>!t.app_name||!a.has(t.app_name))}),T=k(()=>N.value.length+(U.value.length?1:0));function P(a){return(a||"?").charAt(0).toUpperCase()}function x(a){F.push(`/apps/${encodeURIComponent(a)}`)}async function _(){V.value=!0;try{const[a,t]=await Promise.all([r("products/list",{}),r("apps/list",{})]);f.value=a??[],$.value=t??[]}catch(a){b(a?.message??"获取应用列表失败")}finally{V.value=!1}}const y=v(null),M=v(!1),n=B({id:0,name:"",image_name:"",remark:"",enabled:!0});function S(a){M.value=!!a,n.id=a?.id??0,n.name=a?.name??"",n.image_name=a?.image_name??"",n.remark=a?.remark??"",n.enabled=a?!!a.enabled:!0,y.value?.showModal()}async function q(){const a={name:n.name,image_name:n.image_name,remark:n.remark,enabled:n.enabled};let t="products/add";M.value&&n.id&&(a.id=Number(n.id),t="products/update");try{await r(t,a),C("保存成功"),y.value?.close(),await _()}catch(s){b(s?.message??"保存失败")}}function E(a){window.confirm(`删除应用「${a.name}」?(其下若有区域部署将被拒绝)`)&&r("products/del",{id:a.id}).then(()=>{C("已删除"),_()}).catch(t=>b(t?.message??"删除失败"))}async function I(a){const t=c[a.id];if(t)try{await r("apps/assign",{id:a.id,app_name:t}),C(`已归位到「${t}」`),delete c[a.id],await _()}catch(s){b(s?.message??"归位失败")}}return G(_),(a,t)=>(i(),l("div",null,[e("div",X,[t[7]||(t[7]=e("div",null,[e("h2",{class:"text-lg font-semibold text-slate-800"},"应用中心"),e("p",{class:"text-sm text-slate-400 mt-1 max-w-3xl"},[p(" 一张卡片 = 一个 "),e("span",{class:"chip chip-app"},"应用"),p(",卡片里是它在各区域的 "),e("span",{class:"chip chip-dep"},"部署"),p(" 概况。 点卡片进入应用详情:编辑应用、部署新环境、升级服务、改各项配置。 ")])],-1)),e("button",{class:"btn btn-primary btn-sm text-white",onClick:t[0]||(t[0]=s=>S())},"+ 添加应用")]),V.value?(i(),l("div",Y,[...t[8]||(t[8]=[e("span",{class:"loading loading-spinner loading-sm"},null,-1)])])):T.value?(i(),l("div",tt,[(i(!0),l(u,null,h(N.value,s=>(i(),l("article",{key:s.product.name,class:w(["app-card",{off:!s.product.enabled}]),tabindex:"0",role:"button",onClick:o=>x(s.product.name),onKeydown:[D(g(o=>x(s.product.name),["prevent"]),["enter"]),D(g(o=>x(s.product.name),["prevent"]),["space"])]},[e("div",st,[e("div",at,d(P(s.product.name)),1),e("div",nt,[e("div",ot,d(s.product.name),1),e("div",lt,d(s.product.image_name?"🐳 "+s.product.image_name:"未设置默认镜像"),1)]),s.product.enabled?A("",!0):(i(),l("span",it,"停用"))]),e("p",dt,d(s.product.remark||"—"),1),e("div",rt,[e("div",ct,[e("div",{class:w(["ac-stat-n",{zero:!s.deployments.length}])},d(s.deployments.length),3),t[9]||(t[9]=e("div",{class:"ac-stat-l"},"部署",-1))]),e("div",pt,[e("div",{class:w(["ac-stat-n",{zero:!s.okCount}])},d(s.okCount),3),t[10]||(t[10]=e("div",{class:"ac-stat-l"},"已接入",-1))]),e("div",ut,[e("div",{class:w(["ac-stat-n",s.pendingCount?"warn":"zero"])},d(s.pendingCount),3),t[11]||(t[11]=e("div",{class:"ac-stat-l"},"待部署",-1))])]),e("div",mt,[s.deployments.length?(i(!0),l(u,{key:0},h(s.deployments,o=>(i(),l("span",{key:o.id,class:"chip chip-dep"},[p(d(o.region||"未指定"),1),o.status==="pending"?(i(),l(u,{key:0},[p(" · 待部署")],64)):A("",!0)]))),128)):(i(),l("span",vt,"还没有任何部署"))]),e("div",{class:"ac-foot",onClick:t[1]||(t[1]=g(()=>{},["stop"]))},[e("button",{class:"btn btn-ghost btn-xs",onClick:o=>S(s.product)},"编辑",8,bt),e("button",{class:"btn btn-ghost btn-xs text-red-500",onClick:o=>E(s.product)},"删除",8,ft),e("button",{class:"btn btn-primary btn-xs text-white",onClick:o=>x(s.product.name)},"进入详情 →",8,xt)])],42,et))),128)),U.value.length?(i(),l("article",_t,[t[13]||(t[13]=J('
未分组部署
需要归位到某个应用
待归位

未填所属应用名、或应用已被删除的历史部署。选一个应用把它归位,之后就能在该应用详情里管理。

',2)),e("div",yt,[(i(!0),l(u,null,h(U.value,s=>(i(),l("div",{key:s.id,class:"orphan-row"},[e("div",ht,[e("div",gt,d(s.name||"部署#"+s.id),1),e("div",kt,"#"+d(s.id)+" · "+d(s.region||"未指定区域"),1)]),m(e("select",{"onUpdate:modelValue":o=>c[s.id]=o,class:"select select-bordered select-xs w-32"},[t[12]||(t[12]=e("option",{value:""},"选择应用…",-1)),(i(!0),l(u,null,h(f.value,o=>(i(),l("option",{key:o.id,value:o.name},d(o.name),9,Ct))),128))],8,wt),[[H,c[s.id]]]),e("button",{class:"btn btn-xs",disabled:!c[s.id],onClick:o=>I(s)},"归位",8,$t)]))),128))])])):A("",!0)])):(i(),l("div",Z," 暂无应用,先「添加应用」 ")),e("dialog",{ref_key:"appDlg",ref:y,class:"modal"},[e("div",Vt,[e("h3",Ut,d(M.value?"编辑应用":"添加应用"),1),t[19]||(t[19]=e("p",{class:"text-xs text-slate-400 mt-1"}," 应用名是关联键:部署、账号作用域、第三方服务配置都按它挂载,改名会断开已有关联。 ",-1)),e("form",{class:"mt-4 space-y-3",onSubmit:g(q,["prevent"])},[e("div",Mt,[t[14]||(t[14]=e("label",{class:"label py-1"},[e("span",{class:"label-text text-sm font-medium"},"应用名 *")],-1)),m(e("input",{"onUpdate:modelValue":t[2]||(t[2]=s=>n.name=s),type:"text",class:"input input-bordered input-sm w-full",required:"",placeholder:"如 Voitrans"},null,512),[[z,n.name]])]),e("div",At,[t[15]||(t[15]=e("label",{class:"label py-1"},[e("span",{class:"label-text text-sm font-medium"},"默认镜像名")],-1)),m(e("input",{"onUpdate:modelValue":t[3]||(t[3]=s=>n.image_name=s),type:"text",class:"input input-bordered input-sm w-full font-mono text-xs",placeholder:"voitrans-a11(新建部署时预填)"},null,512),[[z,n.image_name]])]),e("div",zt,[t[16]||(t[16]=e("label",{class:"label py-1"},[e("span",{class:"label-text text-sm font-medium"},"备注")],-1)),m(e("input",{"onUpdate:modelValue":t[4]||(t[4]=s=>n.remark=s),type:"text",class:"input input-bordered input-sm w-full"},null,512),[[z,n.remark]])]),e("label",Nt,[m(e("input",{"onUpdate:modelValue":t[5]||(t[5]=s=>n.enabled=s),type:"checkbox",class:"toggle toggle-primary toggle-sm"},null,512),[[L,n.enabled]]),t[17]||(t[17]=e("span",{class:"text-sm"},"启用",-1))]),e("div",St,[e("button",{type:"button",class:"btn btn-ghost btn-sm",onClick:t[6]||(t[6]=s=>y.value?.close())},"取消"),t[18]||(t[18]=e("button",{type:"submit",class:"btn btn-primary btn-sm text-white"},"保存",-1))])],32)]),t[20]||(t[20]=e("form",{method:"dialog",class:"modal-backdrop"},[e("button",null,"close")],-1))],512)]))}}),qt=O(Bt,[["__scopeId","data-v-6c9af955"]]);export{qt as default};