You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1 lines
8.5 KiB
1 lines
8.5 KiB
import{g as j,k as G,C as O,c as l,a as e,d as p,F as u,r as g,N as H,l as M,t as d,p as h,q as m,v as N,x as J,y as v,A as k,z as D,o as i,O as F,n as w,m as T,s as Q,_ as W}from"./DMxDLVSv.js";import{u as X}from"./CCZrj3X-.js";import{u as Y}from"./B-sqZCu-.js";import{r as B}from"./7m3DvxFn.js";const Z={class:"flex items-start justify-between mb-5 flex-wrap gap-3"},tt={key:0,class:"bg-white rounded-xl border border-slate-100 py-16 text-center"},et={key:1,class:"bg-white rounded-xl border border-slate-100 py-16 text-center text-slate-400"},st={key:2,class:"app-grid"},at=["onClick","onKeydown"],nt={class:"ac-head"},ot={class:"ac-logo"},lt={class:"min-w-0 flex-1"},it={class:"ac-title"},dt={class:"ac-meta"},rt={key:0,class:"chip"},ct={class:"ac-remark"},pt={class:"ac-stats"},ut={class:"ac-stat"},mt={class:"ac-stat"},vt={class:"ac-stat"},bt={class:"ac-regions"},ft={key:1,class:"text-xs text-slate-300"},xt=["onClick"],_t=["onClick"],yt=["onClick"],gt={key:0,class:"app-card orphan"},ht={class:"orphan-list"},kt={class:"min-w-0"},wt={class:"text-sm font-medium text-slate-700 truncate"},Ct={class:"text-[11px] text-slate-400 font-mono"},$t=["onUpdate:modelValue"],Vt=["value"],Ut=["disabled","onClick"],At={class:"modal-box max-w-lg"},Mt={class:"font-bold text-lg"},Nt={class:"form-control"},zt={class:"form-control"},St={class:"form-control"},Dt={class:"flex items-center gap-2 cursor-pointer pt-1"},Ft={class:"modal-action"},Tt=j({__name:"index",setup(Bt){const{consoleApi:r}=X(),{success:C,error:b}=Y(),K=G(),f=v([]),$=v([]),V=v(!1),c=D({}),P=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}),z=k(()=>f.value.map(a=>{const t=P.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))}),q=k(()=>z.value.length+(U.value.length?1:0));function E(a){return(a||"?").charAt(0).toUpperCase()}function x(a){K.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),A=v(!1),n=D({id:0,name:"",image_name:"",remark:"",enabled:!0});function S(a){A.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 I(){const a={name:n.name,image_name:n.image_name,remark:n.remark,enabled:n.enabled};let t="products/add";A.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 L(a){window.confirm(`删除应用「${a.name}」?(其下若有区域部署将被拒绝)`)&&r("products/del",{id:a.id}).then(()=>{C("已删除"),_()}).catch(t=>b(t?.message??"删除失败"))}async function R(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 O(_),(a,t)=>(i(),l("div",null,[e("div",Z,[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",tt,[...t[8]||(t[8]=[e("span",{class:"loading loading-spinner loading-sm"},null,-1)])])):q.value?(i(),l("div",st,[(i(!0),l(u,null,g(z.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:[F(h(o=>x(s.product.name),["prevent"]),["enter"]),F(h(o=>x(s.product.name),["prevent"]),["space"])]},[e("div",nt,[e("div",ot,d(E(s.product.name)),1),e("div",lt,[e("div",it,d(s.product.name),1),e("div",dt,d(s.product.image_name?"🐳 "+s.product.image_name:"未设置默认镜像"),1)]),s.product.enabled?M("",!0):(i(),l("span",rt,"停用"))]),e("p",ct,d(s.product.remark||"—"),1),e("div",pt,[e("div",ut,[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",mt,[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",vt,[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",bt,[s.deployments.length?(i(!0),l(u,{key:0},g(s.deployments,o=>(i(),l("span",{key:o.id,class:"chip chip-dep"},[p(d(T(B)(o.region)),1),o.status==="pending"?(i(),l(u,{key:0},[p(" · 待部署")],64)):M("",!0)]))),128)):(i(),l("span",ft,"还没有任何部署"))]),e("div",{class:"ac-foot",onClick:t[1]||(t[1]=h(()=>{},["stop"]))},[e("button",{class:"btn btn-ghost btn-xs",onClick:o=>S(s.product)},"编辑",8,xt),e("button",{class:"btn btn-ghost btn-xs text-red-500",onClick:o=>L(s.product)},"删除",8,_t),e("button",{class:"btn btn-primary btn-xs text-white",onClick:o=>x(s.product.name)},"进入详情 →",8,yt)])],42,at))),128)),U.value.length?(i(),l("article",gt,[t[13]||(t[13]=H('<div class="ac-head" data-v-80f99751><div class="ac-logo" data-v-80f99751>?</div><div class="min-w-0 flex-1" data-v-80f99751><div class="ac-title" data-v-80f99751>未分组部署</div><div class="ac-meta" data-v-80f99751>需要归位到某个应用</div></div><span class="chip chip-warn" data-v-80f99751>待归位</span></div><p class="ac-remark" data-v-80f99751>未填所属应用名、或应用已被删除的历史部署。选一个应用把它归位,之后就能在该应用详情里管理。</p>',2)),e("div",ht,[(i(!0),l(u,null,g(U.value,s=>(i(),l("div",{key:s.id,class:"orphan-row"},[e("div",kt,[e("div",wt,d(s.name||"部署#"+s.id),1),e("div",Ct,"#"+d(s.id)+" · "+d(T(B)(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,g(f.value,o=>(i(),l("option",{key:o.id,value:o.name},d(o.name),9,Vt))),128))],8,$t),[[Q,c[s.id]]]),e("button",{class:"btn btn-xs",disabled:!c[s.id],onClick:o=>R(s)},"归位",8,Ut)]))),128))])])):M("",!0)])):(i(),l("div",et," 暂无应用,先「添加应用」 ")),e("dialog",{ref_key:"appDlg",ref:y,class:"modal"},[e("div",At,[e("h3",Mt,d(A.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:h(I,["prevent"])},[e("div",Nt,[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),[[N,n.name]])]),e("div",zt,[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),[[N,n.image_name]])]),e("div",St,[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),[[N,n.remark]])]),e("label",Dt,[m(e("input",{"onUpdate:modelValue":t[5]||(t[5]=s=>n.enabled=s),type:"checkbox",class:"toggle toggle-primary toggle-sm"},null,512),[[J,n.enabled]]),t[17]||(t[17]=e("span",{class:"text-sm"},"启用",-1))]),e("div",Ft,[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)]))}}),It=W(Tt,[["__scopeId","data-v-80f99751"]]);export{It as default};
|
|
|