- 新增 backend/app/modules/compute_gateway(client/sync)计算网关模块 - 新增 backend/app/workers/compute_poller 计算轮询 worker - 新增 compute/agent/process_manager 进程管理器 - 新增 scripts/ 脚本目录 - 更新 Docker 部署配置(app/compute/nginx) - 更新后端平台 API、数据库 SQL、core 配置 - 更新前端多个视图组件及 API 模块 - 重构 frontend/dist 构建产物(新 hash) - 更新多项文档 Co-Authored-By: Claude <noreply@anthropic.com>
2 lines
15 KiB
JavaScript
2 lines
15 KiB
JavaScript
import{E as ve,a as ye}from"./el-form-item-Bq0n_p5a.js";import{E as we}from"./index-h5FkzAP_.js";import{E as he}from"./index-BNsCyG4A.js";import{E as Ve}from"./index-ByhS8A1d.js";import{E as Ce,a as Ee}from"./el-select-BD70by95.js";import{E as ke}from"./el-dialog-C3T3IeSf.js";import{E as xe}from"./el-input-number-Bg2C0S8w.js";import{E as Ne}from"./el-progress-Dz5Z3t_E.js";import{E as Ue}from"./el-space-Dgiuu1ME.js";import{E as $e}from"./el-switch-DflKYtBf.js";import{a as je,E as Pe}from"./el-table-C7Zx0Bmo.js";import{a as Ge,E as Ie}from"./el-tab-pane-BPBw4wQ7.js";import{v as Te}from"./directive-B1cwmVOz.js";import{aF as T,aG as N,aH as Le,d as Se,y as c,D as qe,G as De,ah as Be,K as Fe,c as v,q as i,aa as u,g as J,s as t,w as a,ac as ze,j as G,o as f,x as d,M as K,ad as Q,e as I,z as Re,A as x,v as Ae}from"./index-Ds9AETjS.js";import"./el-scrollbar-CF42LNzg.js";import"./el-popper-D1tByNLb.js";/* empty css */import"./el-tooltip-l0sNRNKZ.js";import"./el-checkbox-pV3o_8iy.js";import{_ as Me}from"./_plugin-vue_export-helper-DlAUqK2U.js";import"./castArray-BWI4UxBy.js";import"./_baseClone-CZxxnGCv.js";import"./raf-zQ00nuMI.js";import"./index-B0if-AHo.js";import"./index-BSbCLbaz.js";import"./index-sWKLi7bH.js";import"./vnode-CBiWHFw7.js";import"./index-CQlF36Lk.js";import"./scroll-DVmMv0d9.js";import"./clamp-CyhADbdq.js";import"./toNumber-DrayciwT.js";import"./_baseIteratee-82gB5Yov.js";import"./index-RtwaMutE.js";import"./use-dialog-gWD8AZr4.js";import"./index-jBnYrPdD.js";import"./index-2LOSO4Pw.js";import"./validator-D1MwuZXj.js";import"./debounce-D6mJVDYC.js";import"./omit-BzI1MV_K.js";const Oe=()=>T("/compute/nodes"),He=m=>N("/compute/nodes",m),Je=(m,U)=>Le(`/compute/nodes/${m}`,U),Ke=m=>N(`/compute/nodes/${m}/test-connection`),Qe=m=>N(`/compute/nodes/${m}/enable`),We=m=>N(`/compute/nodes/${m}/disable`),Xe=m=>N(`/compute/nodes/${m}/drain`),Ye=()=>T("/compute/gpus"),Ze=()=>T("/compute/queue"),et=m=>T(`/compute/nodes/${m}/replicas`),tt={class:"compute-page"},lt={class:"compute-header"},at={class:"header-actions"},ot={key:0,class:"last-updated"},nt={class:"summary-grid"},st={class:"summary-tile"},ut={class:"summary-tile"},it={class:"summary-tile"},dt={class:"summary-tile"},rt={class:"mono"},mt={class:"muted mono"},pt={class:"muted"},_t={class:"muted"},ct={key:0,class:"muted"},ft={class:"muted"},gt={class:"replica-toolbar"},bt={key:0,class:"muted"},vt={class:"node-form-grid"},yt=Se({__name:"ComputeNodesView",setup(m){const U=ze(),ee=Ae(),L=c(String(U.query.tab||"nodes")),S=c(!0),q=c(!1),y=c([]),$=c([]),D=c([]),B=c([]),b=c(""),F=c(""),h=c(!1),C=c("create"),z=c(!1),n=Re({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 R=null,A=!1;const W=G(()=>y.value.find(o=>o.id===b.value)),te=G(()=>y.value.filter(o=>o.enabled).length),le=G(()=>$.value.filter(o=>o.status==="busy"||o.status==="reserved").length),ae=G(()=>y.value.reduce((o,l)=>o+l.current_running_jobs,0));qe(()=>U.query.tab,o=>{L.value=String(o||"nodes")});async function E(o={}){if(A)return;A=!0;const l=o.showLoading??!1,r=o.showButtonLoading??!1;l&&(S.value=!0),r&&(q.value=!0);try{const[s,w,M]=await Promise.all([Oe(),Ye(),Ze()]);y.value=s,$.value=w,D.value=M,(!b.value||!s.some(V=>V.id===b.value))&&s.length&&(b.value=s[0].id),await X(),F.value=new Date().toLocaleTimeString("zh-CN",{hour12:!1})}finally{l&&(S.value=!1),r&&(q.value=!1),A=!1}}async function X(){if(!b.value){B.value=[];return}B.value=await et(b.value)}async function oe(o){await ee.replace({path:"/compute",query:{tab:String(o)}})}async function j(o,l){const r=String(l.id);if(o==="enable"&&await Qe(r),o==="disable"&&await We(r),o==="drain"&&await Xe(r),o==="test"){const s=await Ke(r);s.success?x.success(`连接成功,发现 ${s.gpu_count} 张 GPU,延迟 ${s.latency_ms}ms`):x.error(s.error||"连接失败")}await E()}function ne(){Object.assign(n,{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 se(){ne(),C.value="create",h.value=!0}function ue(o){var l;Object.assign(n,{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:((l=o.tags)==null?void 0:l.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||""}),C.value="edit",h.value=!0}function ie(){const o=n.tags_text.replace(/,/g,",").split(",").map(l=>l.trim()).filter(Boolean);return{code:n.code.trim(),name:n.name.trim()||n.code.trim(),api_base_url:n.api_base_url.trim().replace(/\/$/,""),file_gateway_url:(n.file_gateway_url||n.api_base_url).trim().replace(/\/$/,""),enabled:n.enabled,scheduler_status:n.scheduler_status,scheduler_weight:Number(n.scheduler_weight)||0,tags:o,max_parallel_jobs:Number(n.max_parallel_jobs)||1,data_root:n.data_root.trim()||"/data/yg-ft",model_root:n.model_root.trim()||"/data/yg-ft/models",log_root:n.log_root.trim()||"/opt/yg-ft/logs/training",description:n.description.trim()}}async function de(){const o=ie();if(!o.code||!o.api_base_url){x.warning("请填写节点编码和 Compute API 地址");return}z.value=!0;try{C.value==="create"?(await He(o),x.success("节点已创建")):(await Je(n.id,o),x.success("节点配置已更新")),h.value=!1,await E()}finally{z.value=!1}}function re(o){return o==="online"?"success":o==="draining"||o==="maintenance"?"warning":"info"}function me(o){return o==="running"?"success":o==="syncing"||o==="queued"?"warning":o==="failed"?"danger":"info"}function pe(o){return o==="busy"?"success":o==="reserved"?"warning":"info"}return De(()=>{E({showLoading:!0}),R=setInterval(()=>E(),5e3)}),Be(()=>{R&&clearInterval(R)}),(o,l)=>{const r=he,s=Pe,w=Ve,M=Ue,V=je,P=Ie,O=Ne,k=Ee,Y=Ce,_e=Ge,g=we,p=ye,Z=xe,ce=$e,fe=ve,ge=ke,be=Te;return Fe((f(),v("section",tt,[i("header",lt,[l[20]||(l[20]=i("div",null,[i("h1",null,"算力节点"),i("p",null,"维护训练算力节点、GPU 状态、任务队列和模型/数据集本地副本。")],-1)),i("div",at,[F.value?(f(),v("span",ot,"更新 "+u(F.value),1)):J("",!0),t(r,{type:"primary",onClick:se},{default:a(()=>[...l[18]||(l[18]=[d("新增节点",-1)])]),_:1}),t(r,{loading:q.value,onClick:l[0]||(l[0]=e=>E({showButtonLoading:!0}))},{default:a(()=>[...l[19]||(l[19]=[d("刷新",-1)])]),_:1},8,["loading"])])]),i("div",nt,[i("div",st,[l[21]||(l[21]=i("span",null,"在线节点",-1)),i("strong",null,u(te.value)+" / "+u(y.value.length),1)]),i("div",ut,[l[22]||(l[22]=i("span",null,"GPU 占用",-1)),i("strong",null,u(le.value)+" / "+u($.value.length),1)]),i("div",it,[l[23]||(l[23]=i("span",null,"运行任务",-1)),i("strong",null,u(ae.value),1)]),i("div",dt,[l[24]||(l[24]=i("span",null,"队列任务",-1)),i("strong",null,u(D.value.length),1)])]),t(_e,{modelValue:L.value,"onUpdate:modelValue":l[2]||(l[2]=e=>L.value=e),class:"compute-tabs",onTabChange:oe},{default:a(()=>[t(P,{label:"节点",name:"nodes"},{default:a(()=>[t(V,{data:y.value,height:"100%"},{default:a(()=>[t(s,{prop:"code",label:"节点编码","min-width":"150"}),t(s,{prop:"name",label:"节点名称","min-width":"150"}),t(s,{label:"状态",width:"120"},{default:a(({row:e})=>[t(w,{type:re(e.scheduler_status)},{default:a(()=>[d(u(e.scheduler_status),1)]),_:2},1032,["type"])]),_:1}),t(s,{label:"启用",width:"90"},{default:a(({row:e})=>[t(w,{type:e.enabled?"success":"info"},{default:a(()=>[d(u(e.enabled?"启用":"停用"),1)]),_:2},1032,["type"])]),_:1}),t(s,{prop:"scheduler_weight",label:"权重",width:"90"}),t(s,{label:"标签","min-width":"220"},{default:a(({row:e})=>[t(M,{wrap:""},{default:a(()=>[(f(!0),v(K,null,Q(e.tags,_=>(f(),I(w,{key:_,effect:"plain"},{default:a(()=>[d(u(_),1)]),_:2},1024))),128))]),_:2},1024)]),_:1}),t(s,{label:"任务/GPU",width:"120"},{default:a(({row:e})=>[d(u(e.current_running_jobs)+" / "+u(e.gpu_count),1)]),_:1}),t(s,{label:"服务地址","min-width":"260"},{default:a(({row:e})=>[i("div",rt,u(e.api_base_url),1),i("div",mt,u(e.file_gateway_url),1)]),_:1}),t(s,{label:"操作",width:"330",fixed:"right"},{default:a(({row:e})=>[t(r,{size:"small",onClick:_=>ue(e)},{default:a(()=>[...l[25]||(l[25]=[d("编辑",-1)])]),_:1},8,["onClick"]),t(r,{size:"small",onClick:_=>j("test",e)},{default:a(()=>[...l[26]||(l[26]=[d("测试",-1)])]),_:1},8,["onClick"]),e.enabled?(f(),I(r,{key:0,size:"small",onClick:_=>j("disable",e)},{default:a(()=>[...l[27]||(l[27]=[d("停用",-1)])]),_:1},8,["onClick"])):(f(),I(r,{key:1,size:"small",type:"primary",onClick:_=>j("enable",e)},{default:a(()=>[...l[28]||(l[28]=[d("启用",-1)])]),_:1},8,["onClick"])),t(r,{size:"small",type:"warning",plain:"",onClick:_=>j("drain",e)},{default:a(()=>[...l[29]||(l[29]=[d("维护",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])]),_:1}),t(P,{label:"GPU",name:"gpus"},{default:a(()=>[t(V,{data:$.value,height:"100%"},{default:a(()=>[t(s,{label:"GPU","min-width":"220"},{default:a(({row:e})=>[i("strong",null,u(e.node_code)+" / GPU "+u(e.id),1),i("div",pt,u(e.name),1)]),_:1}),t(s,{label:"状态",width:"100"},{default:a(({row:e})=>[t(w,{type:pe(e.status)},{default:a(()=>[d(u(e.status),1)]),_:2},1032,["type"])]),_:1}),t(s,{label:"利用率","min-width":"180"},{default:a(({row:e})=>[t(O,{percentage:e.gpu_percent,"stroke-width":8},null,8,["percentage"])]),_:1}),t(s,{label:"显存","min-width":"190"},{default:a(({row:e})=>[t(O,{percentage:Math.round(e.memory_percent),"stroke-width":8},null,8,["percentage"]),i("span",_t,u(e.memory_used_gb)+" / "+u(e.memory_total_gb)+" GB",1)]),_:1}),t(s,{label:"温度/功耗",width:"150"},{default:a(({row:e})=>[d(u(e.temperature)+" C / "+u(e.power_w)+" W",1)]),_:1}),t(s,{label:"进程","min-width":"220"},{default:a(({row:e})=>{var _;return[(_=e.processes)!=null&&_.length?J("",!0):(f(),v("span",ct,"空闲")),(f(!0),v(K,null,Q(e.processes,H=>(f(),v("div",{key:H.pid},[d(u(H.task_name)+" ",1),i("span",ft,"PID "+u(H.pid),1)]))),128))]}),_:1})]),_:1},8,["data"])]),_:1}),t(P,{label:"队列",name:"queue"},{default:a(()=>[t(V,{data:D.value,height:"100%"},{default:a(()=>[t(s,{prop:"name",label:"任务名称","min-width":"200"}),t(s,{label:"状态",width:"110"},{default:a(({row:e})=>[t(w,{type:me(e.status)},{default:a(()=>[d(u(e.status),1)]),_:2},1032,["type"])]),_:1}),t(s,{label:"进度","min-width":"220"},{default:a(({row:e})=>[t(O,{percentage:e.progress,"stroke-width":8},null,8,["percentage"])]),_:1}),t(s,{prop:"compute_node_id",label:"节点",width:"140"}),t(s,{label:"GPU",width:"120"},{default:a(({row:e})=>{var _;return[d(u(((_=e.gpus)==null?void 0:_.join(", "))||"-"),1)]}),_:1}),t(s,{prop:"create_time",label:"创建时间",width:"190"})]),_:1},8,["data"])]),_:1}),t(P,{label:"资源副本",name:"replicas"},{default:a(()=>[i("div",gt,[t(Y,{modelValue:b.value,"onUpdate:modelValue":l[1]||(l[1]=e=>b.value=e),filterable:"",onChange:X},{default:a(()=>[(f(!0),v(K,null,Q(y.value,e=>(f(),I(k,{key:e.id,label:`${e.code} - ${e.name}`,value:e.id},null,8,["label","value"]))),128))]),_:1},8,["modelValue"]),W.value?(f(),v("span",bt,"当前节点 "+u(W.value.api_base_url),1)):J("",!0)]),t(V,{data:B.value,height:"100%"},{default:a(()=>[t(s,{prop:"resource_type",label:"资源类型",width:"110"}),t(s,{prop:"resource_id",label:"资源 ID","min-width":"180"}),t(s,{prop:"local_path",label:"本地路径","min-width":"300"}),t(s,{prop:"status",label:"状态",width:"110"}),t(s,{prop:"sync_status",label:"同步状态",width:"120"}),t(s,{prop:"create_time",label:"创建时间",width:"190"})]),_:1},8,["data"])]),_:1})]),_:1},8,["modelValue"]),t(ge,{modelValue:h.value,"onUpdate:modelValue":l[17]||(l[17]=e=>h.value=e),title:C.value==="create"?"新增算力节点":"编辑算力节点",width:"720px"},{footer:a(()=>[t(r,{onClick:l[16]||(l[16]=e=>h.value=!1)},{default:a(()=>[...l[30]||(l[30]=[d("取消",-1)])]),_:1}),t(r,{type:"primary",loading:z.value,onClick:de},{default:a(()=>[...l[31]||(l[31]=[d("保存",-1)])]),_:1},8,["loading"])]),default:a(()=>[t(fe,{"label-width":"130px"},{default:a(()=>[i("div",vt,[t(p,{label:"节点编码",required:""},{default:a(()=>[t(g,{modelValue:n.code,"onUpdate:modelValue":l[3]||(l[3]=e=>n.code=e),disabled:C.value==="edit",placeholder:"gpu-node-01"},null,8,["modelValue","disabled"])]),_:1}),t(p,{label:"节点名称"},{default:a(()=>[t(g,{modelValue:n.name,"onUpdate:modelValue":l[4]||(l[4]=e=>n.name=e),placeholder:"A800 训练节点 01"},null,8,["modelValue"])]),_:1}),t(p,{label:"Compute API",required:""},{default:a(()=>[t(g,{modelValue:n.api_base_url,"onUpdate:modelValue":l[5]||(l[5]=e=>n.api_base_url=e),placeholder:"http://10.0.0.11:19100"},null,8,["modelValue"])]),_:1}),t(p,{label:"File Gateway"},{default:a(()=>[t(g,{modelValue:n.file_gateway_url,"onUpdate:modelValue":l[6]||(l[6]=e=>n.file_gateway_url=e),placeholder:"http://10.0.0.11:19101"},null,8,["modelValue"])]),_:1}),t(p,{label:"调度权重"},{default:a(()=>[t(Z,{modelValue:n.scheduler_weight,"onUpdate:modelValue":l[7]||(l[7]=e=>n.scheduler_weight=e),min:0,max:1e3,"controls-position":"right"},null,8,["modelValue"])]),_:1}),t(p,{label:"最大并行任务"},{default:a(()=>[t(Z,{modelValue:n.max_parallel_jobs,"onUpdate:modelValue":l[8]||(l[8]=e=>n.max_parallel_jobs=e),min:1,max:32,"controls-position":"right"},null,8,["modelValue"])]),_:1}),t(p,{label:"启用状态"},{default:a(()=>[t(ce,{modelValue:n.enabled,"onUpdate:modelValue":l[9]||(l[9]=e=>n.enabled=e),"active-text":"启用","inactive-text":"停用"},null,8,["modelValue"])]),_:1}),t(p,{label:"调度状态"},{default:a(()=>[t(Y,{modelValue:n.scheduler_status,"onUpdate:modelValue":l[10]||(l[10]=e=>n.scheduler_status=e)},{default:a(()=>[t(k,{label:"离线",value:"offline"}),t(k,{label:"在线",value:"online"}),t(k,{label:"维护中",value:"draining"}),t(k,{label:"维护模式",value:"maintenance"})]),_:1},8,["modelValue"])]),_:1})]),t(p,{label:"标签"},{default:a(()=>[t(g,{modelValue:n.tags_text,"onUpdate:modelValue":l[11]||(l[11]=e=>n.tags_text=e),placeholder:"a800, lora, beijing"},null,8,["modelValue"])]),_:1}),t(p,{label:"数据根目录"},{default:a(()=>[t(g,{modelValue:n.data_root,"onUpdate:modelValue":l[12]||(l[12]=e=>n.data_root=e)},null,8,["modelValue"])]),_:1}),t(p,{label:"模型根目录"},{default:a(()=>[t(g,{modelValue:n.model_root,"onUpdate:modelValue":l[13]||(l[13]=e=>n.model_root=e)},null,8,["modelValue"])]),_:1}),t(p,{label:"训练日志目录"},{default:a(()=>[t(g,{modelValue:n.log_root,"onUpdate:modelValue":l[14]||(l[14]=e=>n.log_root=e)},null,8,["modelValue"])]),_:1}),t(p,{label:"备注"},{default:a(()=>[t(g,{modelValue:n.description,"onUpdate:modelValue":l[15]||(l[15]=e=>n.description=e),type:"textarea",rows:3},null,8,["modelValue"])]),_:1})]),_:1})]),_:1},8,["modelValue","title"])])),[[be,S.value]])}}}),nl=Me(yt,[["__scopeId","data-v-5ebf5cb5"]]);export{nl as default};
|