import{E as ke,a as Ne}from"./el-form-item-rya6onmd.js";import{E as xe}from"./index-DbBHj60R.js";import{E as Ee}from"./index-DxH5-_w6.js";import{E as $e}from"./el-tag-C2d1Zfbn.js";import{E as Ue,a as je}from"./el-select-BQaRHu3V.js";import{E as Be}from"./el-dialog-DhFCo7lq.js";import{E as Ge}from"./el-input-number-Cs1MXSA_.js";import{E as Pe}from"./el-progress-qwyMzaE5.js";import{E as De}from"./el-space-Brji4Mfq.js";import{E as Le}from"./el-switch-DCvDahA2.js";import{a as Re,E as Te}from"./el-table-B6qMxzT4.js";import{a as ze,E as Fe}from"./el-tab-pane-kUOhsu5N.js";import{v as qe}from"./directive-BBfPDwlQ.js";import{aF as G,aG as x,aH as Se,d as Ie,y as p,D as Me,G as Ae,ah as Oe,K as Ke,c as V,q as i,aa as u,g as Y,s as l,w as a,ac as He,j as T,o as g,x as d,f as b,M as Z,ad as ee,e as z,z as Je,A as w,v as Qe}from"./index-D5veDkuG.js";import"./el-scrollbar-GFOwBTUz.js";import"./el-popper-DDJTxf27.js";import"./el-tooltip-l0sNRNKZ.js";import"./el-checkbox-D6iLoXkw.js";import{s as j,a as B}from"./status-Dl1fykxa.js";import{_ as We}from"./_plugin-vue_export-helper-DlAUqK2U.js";import"./castArray-BDIbf8ih.js";import"./_baseClone-BuqHm105.js";import"./raf-Dsox5IbR.js";import"./index-DDY6aSpq.js";import"./index-BT1A2I5c.js";import"./index-DmAaj_YO.js";import"./vnode-CYZHqsIy.js";import"./index-DbuKXJ7V.js";import"./scroll-DswMXu1y.js";import"./clamp-Ddg8_Yc2.js";import"./toNumber-a8w_gs0u.js";import"./_baseIteratee-N-G7GeYE.js";import"./index-BNyn2v9n.js";import"./use-dialog-BGZ6Fb7L.js";import"./index-fqcbYM03.js";import"./index-APLq0PKf.js";import"./validator-CddYkkyy.js";import"./debounce-D3zKL4rk.js";import"./omit-DxQEBv1Z.js";const Xe=()=>G("/compute/nodes"),Ye=m=>x("/compute/nodes",m),Ze=(m,v)=>Se(`/compute/nodes/${m}`,v),et=m=>x(`/compute/nodes/${m}/test-connection`),tt=m=>x(`/compute/nodes/${m}/enable`),lt=m=>x(`/compute/nodes/${m}/disable`),at=m=>x(`/compute/nodes/${m}/drain`),ot=()=>G("/compute/gpus"),st=()=>G("/compute/queue"),nt=m=>G(`/compute/nodes/${m}/replicas`),ut=m=>G(`/compute/nodes/${m}/replicas/drift`),it=(m,v)=>x(`/compute/nodes/${m}/replicas/repair`,v!=null&&v.length?{replica_ids:v}:{}),dt={class:"compute-page"},rt={class:"compute-header"},mt={class:"header-actions"},pt={key:0,class:"last-updated"},_t={class:"summary-grid"},ft={class:"summary-tile"},ct={class:"summary-tile"},gt={class:"summary-tile"},bt={class:"summary-tile"},vt={class:"mono"},yt={class:"muted mono"},ht={class:"muted"},wt={class:"muted"},Vt={key:0,class:"muted"},Ct={class:"muted"},kt={class:"replica-toolbar"},Nt={key:0,class:"muted"},xt={class:"node-form-grid"},Et=Ie({__name:"ComputeNodesView",setup(m){const v=He(),se=Qe(),F=p(String(v.query.tab||"nodes")),q=p(!0),S=p(!1),I=p(!1),M=p(!1),C=p([]),P=p([]),A=p([]),k=p([]),c=p(""),O=p(""),N=p(!1),E=p("create"),K=p(!1),s=Je({id:"",code:"",name:"",api_base_url:"",file_gateway_url:"",enabled:!0,scheduler_status:"offline",scheduler_weight:100,tags_text:"",max_parallel_jobs:1,data_root:"/data/yg-ft",model_root:"/data/yg-ft/models",log_root:"/opt/yg-ft/logs/training",description:""});let H=null,J=!1;const te=T(()=>C.value.find(o=>o.id===c.value)),ne=T(()=>C.value.filter(o=>o.enabled).length),ue=T(()=>P.value.filter(o=>o.status==="busy"||o.status==="reserved").length),ie=T(()=>C.value.reduce((o,t)=>o+t.current_running_jobs,0));function $t(o){return o}Me(()=>v.query.tab,o=>{F.value=String(o||"nodes")});async function $(o={}){if(!J){J=!0,o.showLoading&&(q.value=!0),o.showButtonLoading&&(S.value=!0);try{const[t,r,n]=await Promise.all([Xe(),ot(),st()]);C.value=t,P.value=r,A.value=n,(!c.value||!t.some(y=>y.id===c.value))&&t.length&&(c.value=t[0].id),await Q(),O.value=new Date().toLocaleTimeString("zh-CN",{hour12:!1})}finally{o.showLoading&&(q.value=!1),o.showButtonLoading&&(S.value=!1),J=!1}}}async function Q(){if(!c.value){k.value=[];return}k.value=await nt(c.value)}async function de(o){await se.replace({path:"/compute",query:{tab:String(o)}})}async function D(o,t){const r=String(t.id);if(o==="enable"&&await tt(r),o==="disable"&&await lt(r),o==="drain"&&await at(r),o==="test"){const n=await et(r);n.success?w.success(`连接成功,发现 ${n.gpu_count} 张 GPU,延迟 ${n.latency_ms}ms`):w.error(n.error||"连接失败")}await $()}async function re(){if(c.value){I.value=!0;try{const o=await ut(c.value);k.value=o.items||[],w.success(o.drifted?`检测完成,发现 ${o.drifted} 个异常副本`:"检测完成,副本状态正常")}finally{I.value=!1}}}async function me(){var t;if(!c.value)return;const o=k.value.filter(r=>["drifted","failed","repair_pending"].includes(r.sync_status));if(!o.length){w.info("暂无需要修复的副本");return}M.value=!0;try{const r=await it(c.value,o.map(n=>n.id));k.value=r.replicas||[],(t=r.failed)!=null&&t.length?w.warning(`修复完成,失败 ${r.failed.length} 个`):w.success("副本修复完成"),await Q()}finally{M.value=!1}}function pe(){Object.assign(s,{id:"",code:"",name:"",api_base_url:"",file_gateway_url:"",enabled:!0,scheduler_status:"offline",scheduler_weight:100,tags_text:"",max_parallel_jobs:1,data_root:"/data/yg-ft",model_root:"/data/yg-ft/models",log_root:"/opt/yg-ft/logs/training",description:""})}function _e(){pe(),E.value="create",N.value=!0}function fe(o){var t;Object.assign(s,{id:o.id,code:o.code,name:o.name,api_base_url:o.api_base_url,file_gateway_url:o.file_gateway_url,enabled:o.enabled,scheduler_status:o.scheduler_status,scheduler_weight:o.scheduler_weight,tags_text:((t=o.tags)==null?void 0:t.join(", "))||"",max_parallel_jobs:o.max_parallel_jobs,data_root:o.data_root,model_root:o.model_root,log_root:o.log_root,description:o.description||""}),E.value="edit",N.value=!0}function ce(){const o=s.tags_text.replace(/,/g,",").split(",").map(t=>t.trim()).filter(Boolean);return{code:s.code.trim(),name:s.name.trim()||s.code.trim(),api_base_url:s.api_base_url.trim().replace(/\/$/,""),file_gateway_url:(s.file_gateway_url||s.api_base_url).trim().replace(/\/$/,""),enabled:s.enabled,scheduler_status:s.scheduler_status,scheduler_weight:Number(s.scheduler_weight)||0,tags:o,max_parallel_jobs:Number(s.max_parallel_jobs)||1,data_root:s.data_root.trim()||"/data/yg-ft",model_root:s.model_root.trim()||"/data/yg-ft/models",log_root:s.log_root.trim()||"/opt/yg-ft/logs/training",description:s.description.trim()}}async function ge(){const o=ce();if(!o.code||!o.api_base_url){w.warning("请填写节点编码和 Compute API 地址");return}K.value=!0;try{E.value==="create"?(await Ye(o),w.success("节点已创建")):(await Ze(s.id,o),w.success("节点配置已更新")),N.value=!1,await $()}finally{K.value=!1}}function be(o){const t=Number(o||0);return t?t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:t<1024*1024*1024?`${(t/1024/1024).toFixed(1)} MB`:`${(t/1024/1024/1024).toFixed(2)} GB`:"-"}function le(o){return o?new Date(o).toLocaleString("zh-CN"):"-"}return Ae(()=>{$({showLoading:!0}),H=setInterval(()=>$(),5e3)}),Oe(()=>{H&&clearInterval(H)}),(o,t)=>{const r=Ee,n=Te,y=$e,ve=De,L=Re,R=Fe,W=Pe,U=je,ae=Ue,ye=ze,h=xe,_=Ne,oe=Ge,he=Le,we=ke,Ve=Be,Ce=qe;return Ke((g(),V("section",dt,[i("header",rt,[t[20]||(t[20]=i("div",null,[i("h1",null,"算力节点"),i("p",null,"维护训练算力节点、GPU 状态、任务队列和模型/数据集本地副本。")],-1)),i("div",mt,[O.value?(g(),V("span",pt,"更新 "+u(O.value),1)):Y("",!0),l(r,{type:"primary",onClick:_e},{default:a(()=>[...t[18]||(t[18]=[d("新增节点",-1)])]),_:1}),l(r,{loading:S.value,onClick:t[0]||(t[0]=e=>$({showButtonLoading:!0}))},{default:a(()=>[...t[19]||(t[19]=[d("刷新",-1)])]),_:1},8,["loading"])])]),i("div",_t,[i("div",ft,[t[21]||(t[21]=i("span",null,"启用节点",-1)),i("strong",null,u(ne.value)+" / "+u(C.value.length),1)]),i("div",ct,[t[22]||(t[22]=i("span",null,"GPU 占用",-1)),i("strong",null,u(ue.value)+" / "+u(P.value.length),1)]),i("div",gt,[t[23]||(t[23]=i("span",null,"运行任务",-1)),i("strong",null,u(ie.value),1)]),i("div",bt,[t[24]||(t[24]=i("span",null,"队列任务",-1)),i("strong",null,u(A.value.length),1)])]),l(ye,{modelValue:F.value,"onUpdate:modelValue":t[2]||(t[2]=e=>F.value=e),class:"compute-tabs",onTabChange:de},{default:a(()=>[l(R,{label:"节点",name:"nodes"},{default:a(()=>[l(L,{data:C.value,height:"100%"},{default:a(()=>[l(n,{prop:"code",label:"节点编码","min-width":"150"}),l(n,{prop:"name",label:"节点名称","min-width":"150"}),l(n,{label:"状态",width:"120"},{default:a(({row:e})=>[l(y,{type:b(j)(e.scheduler_status)},{default:a(()=>[d(u(b(B)(e.scheduler_status)),1)]),_:2},1032,["type"])]),_:1}),l(n,{label:"启用",width:"90"},{default:a(({row:e})=>[l(y,{type:e.enabled?"success":"info"},{default:a(()=>[d(u(e.enabled?"启用":"停用"),1)]),_:2},1032,["type"])]),_:1}),l(n,{prop:"scheduler_weight",label:"权重",width:"90"}),l(n,{label:"标签","min-width":"220"},{default:a(({row:e})=>[l(ve,{wrap:""},{default:a(()=>[(g(!0),V(Z,null,ee(e.tags,f=>(g(),z(y,{key:f,effect:"plain"},{default:a(()=>[d(u(f),1)]),_:2},1024))),128))]),_:2},1024)]),_:1}),l(n,{label:"任务/GPU",width:"120"},{default:a(({row:e})=>[d(u(e.current_running_jobs)+" / "+u(e.gpu_count),1)]),_:1}),l(n,{label:"服务地址","min-width":"260"},{default:a(({row:e})=>[i("div",vt,u(e.api_base_url),1),i("div",yt,u(e.file_gateway_url),1)]),_:1}),l(n,{label:"操作",width:"330",fixed:"right"},{default:a(({row:e})=>[l(r,{size:"small",onClick:f=>fe(e)},{default:a(()=>[...t[25]||(t[25]=[d("编辑",-1)])]),_:1},8,["onClick"]),l(r,{size:"small",onClick:f=>D("test",e)},{default:a(()=>[...t[26]||(t[26]=[d("测试",-1)])]),_:1},8,["onClick"]),e.enabled?(g(),z(r,{key:0,size:"small",onClick:f=>D("disable",e)},{default:a(()=>[...t[27]||(t[27]=[d("停用",-1)])]),_:1},8,["onClick"])):(g(),z(r,{key:1,size:"small",type:"primary",onClick:f=>D("enable",e)},{default:a(()=>[...t[28]||(t[28]=[d("启用",-1)])]),_:1},8,["onClick"])),l(r,{size:"small",type:"warning",plain:"",onClick:f=>D("drain",e)},{default:a(()=>[...t[29]||(t[29]=[d("维护",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])]),_:1}),l(R,{label:"GPU",name:"gpus"},{default:a(()=>[l(L,{data:P.value,height:"100%"},{default:a(()=>[l(n,{label:"GPU","min-width":"220"},{default:a(({row:e})=>[i("strong",null,u(e.node_code)+" / GPU "+u(e.id),1),i("div",ht,u(e.name),1)]),_:1}),l(n,{label:"状态",width:"100"},{default:a(({row:e})=>[l(y,{type:b(j)(e.status)},{default:a(()=>[d(u(b(B)(e.status)),1)]),_:2},1032,["type"])]),_:1}),l(n,{label:"利用率","min-width":"180"},{default:a(({row:e})=>[l(W,{percentage:e.gpu_percent,"stroke-width":8},null,8,["percentage"])]),_:1}),l(n,{label:"显存","min-width":"190"},{default:a(({row:e})=>[l(W,{percentage:Math.round(e.memory_percent),"stroke-width":8},null,8,["percentage"]),i("span",wt,u(e.memory_used_gb)+" / "+u(e.memory_total_gb)+" GB",1)]),_:1}),l(n,{label:"温度/功耗",width:"150"},{default:a(({row:e})=>[d(u(e.temperature)+" C / "+u(e.power_w)+" W",1)]),_:1}),l(n,{label:"进程","min-width":"220"},{default:a(({row:e})=>{var f;return[(f=e.processes)!=null&&f.length?Y("",!0):(g(),V("span",Vt,"空闲")),(g(!0),V(Z,null,ee(e.processes,X=>(g(),V("div",{key:X.pid},[d(u(X.task_name)+" ",1),i("span",Ct,"PID "+u(X.pid),1)]))),128))]}),_:1})]),_:1},8,["data"])]),_:1}),l(R,{label:"队列",name:"queue"},{default:a(()=>[l(L,{data:A.value,height:"100%"},{default:a(()=>[l(n,{prop:"name",label:"任务名称","min-width":"200"}),l(n,{label:"状态",width:"110"},{default:a(({row:e})=>[l(y,{type:b(j)(e.status)},{default:a(()=>[d(u(b(B)(e.status)),1)]),_:2},1032,["type"])]),_:1}),l(n,{label:"进度","min-width":"220"},{default:a(({row:e})=>[l(W,{percentage:e.progress,"stroke-width":8},null,8,["percentage"])]),_:1}),l(n,{prop:"compute_node_id",label:"节点",width:"140"}),l(n,{label:"GPU",width:"120"},{default:a(({row:e})=>{var f;return[d(u(((f=e.gpus)==null?void 0:f.join(", "))||"-"),1)]}),_:1}),l(n,{label:"创建时间",width:"190"},{default:a(({row:e})=>[d(u(le(e.create_time)),1)]),_:1})]),_:1},8,["data"])]),_:1}),l(R,{label:"资源副本",name:"replicas"},{default:a(()=>[i("div",kt,[l(ae,{modelValue:c.value,"onUpdate:modelValue":t[1]||(t[1]=e=>c.value=e),filterable:"",onChange:Q},{default:a(()=>[(g(!0),V(Z,null,ee(C.value,e=>(g(),z(U,{key:e.id,label:`${e.code} - ${e.name}`,value:e.id},null,8,["label","value"]))),128))]),_:1},8,["modelValue"]),te.value?(g(),V("span",Nt,"当前节点 "+u(te.value.api_base_url),1)):Y("",!0),l(r,{loading:I.value,onClick:re},{default:a(()=>[...t[30]||(t[30]=[d("漂移检测",-1)])]),_:1},8,["loading"]),l(r,{type:"primary",loading:M.value,onClick:me},{default:a(()=>[...t[31]||(t[31]=[d("修复副本",-1)])]),_:1},8,["loading"])]),l(L,{data:k.value,height:"100%"},{default:a(()=>[l(n,{prop:"resource_type",label:"资源类型",width:"110"}),l(n,{prop:"resource_id",label:"资源 ID","min-width":"180"}),l(n,{prop:"local_path",label:"本地路径","min-width":"300","show-overflow-tooltip":""}),l(n,{label:"状态",width:"110"},{default:a(({row:e})=>[l(y,{type:b(j)(e.status),size:"small"},{default:a(()=>[d(u(b(B)(e.status)),1)]),_:2},1032,["type"])]),_:1}),l(n,{label:"同步状态",width:"120"},{default:a(({row:e})=>[l(y,{type:b(j)(e.sync_status),size:"small"},{default:a(()=>[d(u(b(B)(e.sync_status)),1)]),_:2},1032,["type"])]),_:1}),l(n,{label:"大小",width:"110"},{default:a(({row:e})=>[d(u(be(e.byte_size)),1)]),_:1}),l(n,{label:"最后检测",width:"190"},{default:a(({row:e})=>[d(u(le(e.last_checked_at)),1)]),_:1})]),_:1},8,["data"])]),_:1})]),_:1},8,["modelValue"]),l(Ve,{modelValue:N.value,"onUpdate:modelValue":t[17]||(t[17]=e=>N.value=e),title:E.value==="create"?"新增算力节点":"编辑算力节点",width:"720px"},{footer:a(()=>[l(r,{onClick:t[16]||(t[16]=e=>N.value=!1)},{default:a(()=>[...t[32]||(t[32]=[d("取消",-1)])]),_:1}),l(r,{type:"primary",loading:K.value,onClick:ge},{default:a(()=>[...t[33]||(t[33]=[d("保存",-1)])]),_:1},8,["loading"])]),default:a(()=>[l(we,{"label-width":"130px"},{default:a(()=>[i("div",xt,[l(_,{label:"节点编码",required:""},{default:a(()=>[l(h,{modelValue:s.code,"onUpdate:modelValue":t[3]||(t[3]=e=>s.code=e),disabled:E.value==="edit",placeholder:"gpu-node-01"},null,8,["modelValue","disabled"])]),_:1}),l(_,{label:"节点名称"},{default:a(()=>[l(h,{modelValue:s.name,"onUpdate:modelValue":t[4]||(t[4]=e=>s.name=e),placeholder:"A800 训练节点 01"},null,8,["modelValue"])]),_:1}),l(_,{label:"Compute API",required:""},{default:a(()=>[l(h,{modelValue:s.api_base_url,"onUpdate:modelValue":t[5]||(t[5]=e=>s.api_base_url=e),placeholder:"http://10.0.0.11:19100"},null,8,["modelValue"])]),_:1}),l(_,{label:"File Gateway"},{default:a(()=>[l(h,{modelValue:s.file_gateway_url,"onUpdate:modelValue":t[6]||(t[6]=e=>s.file_gateway_url=e),placeholder:"http://10.0.0.11:19101"},null,8,["modelValue"])]),_:1}),l(_,{label:"调度权重"},{default:a(()=>[l(oe,{modelValue:s.scheduler_weight,"onUpdate:modelValue":t[7]||(t[7]=e=>s.scheduler_weight=e),min:0,max:1e3,"controls-position":"right"},null,8,["modelValue"])]),_:1}),l(_,{label:"最大并行任务"},{default:a(()=>[l(oe,{modelValue:s.max_parallel_jobs,"onUpdate:modelValue":t[8]||(t[8]=e=>s.max_parallel_jobs=e),min:1,max:32,"controls-position":"right"},null,8,["modelValue"])]),_:1}),l(_,{label:"启用状态"},{default:a(()=>[l(he,{modelValue:s.enabled,"onUpdate:modelValue":t[9]||(t[9]=e=>s.enabled=e),"active-text":"启用","inactive-text":"停用"},null,8,["modelValue"])]),_:1}),l(_,{label:"调度状态"},{default:a(()=>[l(ae,{modelValue:s.scheduler_status,"onUpdate:modelValue":t[10]||(t[10]=e=>s.scheduler_status=e)},{default:a(()=>[l(U,{label:"离线",value:"offline"}),l(U,{label:"在线",value:"online"}),l(U,{label:"维护中",value:"draining"}),l(U,{label:"维护模式",value:"maintenance"})]),_:1},8,["modelValue"])]),_:1})]),l(_,{label:"标签"},{default:a(()=>[l(h,{modelValue:s.tags_text,"onUpdate:modelValue":t[11]||(t[11]=e=>s.tags_text=e),placeholder:"a800, lora, beijing"},null,8,["modelValue"])]),_:1}),l(_,{label:"数据根目录"},{default:a(()=>[l(h,{modelValue:s.data_root,"onUpdate:modelValue":t[12]||(t[12]=e=>s.data_root=e)},null,8,["modelValue"])]),_:1}),l(_,{label:"模型根目录"},{default:a(()=>[l(h,{modelValue:s.model_root,"onUpdate:modelValue":t[13]||(t[13]=e=>s.model_root=e)},null,8,["modelValue"])]),_:1}),l(_,{label:"训练日志目录"},{default:a(()=>[l(h,{modelValue:s.log_root,"onUpdate:modelValue":t[14]||(t[14]=e=>s.log_root=e)},null,8,["modelValue"])]),_:1}),l(_,{label:"备注"},{default:a(()=>[l(h,{modelValue:s.description,"onUpdate:modelValue":t[15]||(t[15]=e=>s.description=e),type:"textarea",rows:3},null,8,["modelValue"])]),_:1})]),_:1})]),_:1},8,["modelValue","title"])])),[[Ce,q.value]])}}}),fl=We(Et,[["__scopeId","data-v-6f93f55a"]]);export{fl as default};