fix(pve): 修复Scan语法错误 + MachineDetail编辑弹窗添加PVE配置

- services/pve.go: 修复 &h.PasswordEnch.Username -> &h.NodeName
- MachineDetail.vue: 编辑弹窗添加PVE主机选择+VMID输入
- 删除macOS自动生成的冲突副本文件
- 重新构建前端dist

[金渐层/K2.6-code-preview🐾]
This commit is contained in:
openclaw
2026-04-20 13:25:51 +08:00
parent 31884e386e
commit 1fcf9cbdef
17 changed files with 30 additions and 16 deletions

View File

@@ -295,7 +295,7 @@ func (s *PVEHostService) GetAll() ([]models.PVEHost, error) {
for rows.Next() {
var h models.PVEHost
var verifySSL int
if err := rows.Scan(&h.ID, &h.Name, &h.Hostname, &h.Port, &h.Username, &h.PasswordEnch.Username, &h.NodeName, &h.PasswordEnc, &verifySSL, &h.CreatedAt, &h.UpdatedAt); err != nil {
if err := rows.Scan(&h.ID, &h.Name, &h.Hostname, &h.Port, &h.Username, &h.NodeName, &h.PasswordEnc, &verifySSL, &h.CreatedAt, &h.UpdatedAt); err != nil {
return nil, err
}
h.VerifySSL = verifySSL == 1
@@ -309,7 +309,7 @@ func (s *PVEHostService) GetByID(id int64) (*models.PVEHost, error) {
var h models.PVEHost
var verifySSL int
err := db.DB.QueryRow(`SELECT id, name, hostname, port, username, node_name, password_enc, verify_ssl, created_at, updated_at FROM pve_hosts WHERE id = ?`, id).
Scan(&h.ID, &h.Name, &h.Hostname, &h.Port, &h.Username, &h.PasswordEnch.Username, &h.NodeName, &h.PasswordEnc, &verifySSL, &h.CreatedAt, &h.UpdatedAt)
Scan(&h.ID, &h.Name, &h.Hostname, &h.Port, &h.Username, &h.NodeName, &h.PasswordEnc, &verifySSL, &h.CreatedAt, &h.UpdatedAt)
if err != nil {
return nil, err
}

View File

@@ -1 +1 @@
import{o as b,c as x,a as o,b as s,w as l,r as g,d as u,u as k,e as v,f as N,g as w,l as z,h as y,E as d,i as C,s as V,j as M}from"./index-BFjouPFU.js";import{_ as A}from"./_plugin-vue_export-helper-DlAUqK2U.js";const B={class:"login-page"},E={class:"login-card"},K={class:"input-wrap"},U={class:"input-wrap"},$={class:"login-guest"},j={__name:"Login",setup(I){const c=k(),a=g({username:"",password:""}),n=g(!1);async function r(){if(!a.value.username||!a.value.password){d.warning("请输入用户名和密码");return}n.value=!0;try{const t=await C(a.value);V(t.data),d.success("登录成功"),c.push("/")}catch{}n.value=!1}async function h(){n.value=!0;try{const t=await M();V(t.data),d.success("已进入访客模式"),c.push("/")}catch{}n.value=!1}return(t,e)=>{const p=u("el-icon"),_=u("el-input"),m=u("el-form-item"),f=u("el-button"),L=u("el-form");return b(),x("div",B,[o("div",E,[e[4]||(e[4]=o("div",{class:"login-header"},[o("div",{class:"logo"},"LM"),o("h1",null,"LAN Manager"),o("p",null,"轻量级局域网资产管理平台")],-1)),s(L,{model:a.value,class:"login-form"},{default:l(()=>[s(m,null,{default:l(()=>[o("div",K,[s(p,{class:"input-icon"},{default:l(()=>[s(v(N))]),_:1}),s(_,{modelValue:a.value.username,"onUpdate:modelValue":e[0]||(e[0]=i=>a.value.username=i),placeholder:"用户名",size:"large",onKeydown:w(r,["enter"])},null,8,["modelValue"])])]),_:1}),s(m,null,{default:l(()=>[o("div",U,[s(p,{class:"input-icon"},{default:l(()=>[s(v(z))]),_:1}),s(_,{modelValue:a.value.password,"onUpdate:modelValue":e[1]||(e[1]=i=>a.value.password=i),type:"password","show-password":"",placeholder:"密码",size:"large",onKeydown:w(r,["enter"])},null,8,["modelValue"])])]),_:1}),s(f,{type:"primary",size:"large",class:"login-btn",loading:n.value,onClick:r},{default:l(()=>[...e[2]||(e[2]=[y("登录",-1)])]),_:1},8,["loading"]),o("div",$,[s(f,{text:"",size:"small",onClick:h},{default:l(()=>[...e[3]||(e[3]=[y("访客模式进入",-1)])]),_:1})])]),_:1},8,["model"])]),e[5]||(e[5]=o("div",{class:"login-footer"}," © LAN Manager ",-1))])}}},q=A(j,[["__scopeId","data-v-92ccba4b"]]);export{q as default};
import{o as b,c as x,a as o,b as s,w as l,r as g,d as u,u as k,e as v,f as N,g as w,l as z,h as y,E as d,i as C,s as V,j as M}from"./index-lpjSKhQ-.js";import{_ as A}from"./_plugin-vue_export-helper-DlAUqK2U.js";const B={class:"login-page"},E={class:"login-card"},K={class:"input-wrap"},U={class:"input-wrap"},$={class:"login-guest"},j={__name:"Login",setup(I){const c=k(),a=g({username:"",password:""}),n=g(!1);async function r(){if(!a.value.username||!a.value.password){d.warning("请输入用户名和密码");return}n.value=!0;try{const t=await C(a.value);V(t.data),d.success("登录成功"),c.push("/")}catch{}n.value=!1}async function h(){n.value=!0;try{const t=await M();V(t.data),d.success("已进入访客模式"),c.push("/")}catch{}n.value=!1}return(t,e)=>{const p=u("el-icon"),_=u("el-input"),m=u("el-form-item"),f=u("el-button"),L=u("el-form");return b(),x("div",B,[o("div",E,[e[4]||(e[4]=o("div",{class:"login-header"},[o("div",{class:"logo"},"LM"),o("h1",null,"LAN Manager"),o("p",null,"轻量级局域网资产管理平台")],-1)),s(L,{model:a.value,class:"login-form"},{default:l(()=>[s(m,null,{default:l(()=>[o("div",K,[s(p,{class:"input-icon"},{default:l(()=>[s(v(N))]),_:1}),s(_,{modelValue:a.value.username,"onUpdate:modelValue":e[0]||(e[0]=i=>a.value.username=i),placeholder:"用户名",size:"large",onKeydown:w(r,["enter"])},null,8,["modelValue"])])]),_:1}),s(m,null,{default:l(()=>[o("div",U,[s(p,{class:"input-icon"},{default:l(()=>[s(v(z))]),_:1}),s(_,{modelValue:a.value.password,"onUpdate:modelValue":e[1]||(e[1]=i=>a.value.password=i),type:"password","show-password":"",placeholder:"密码",size:"large",onKeydown:w(r,["enter"])},null,8,["modelValue"])])]),_:1}),s(f,{type:"primary",size:"large",class:"login-btn",loading:n.value,onClick:r},{default:l(()=>[...e[2]||(e[2]=[y("登录",-1)])]),_:1},8,["loading"]),o("div",$,[s(f,{text:"",size:"small",onClick:h},{default:l(()=>[...e[3]||(e[3]=[y("访客模式进入",-1)])]),_:1})])]),_:1},8,["model"])]),e[5]||(e[5]=o("div",{class:"login-footer"}," © LAN Manager ",-1))])}}},q=A(j,[["__scopeId","data-v-92ccba4b"]]);export{q as default};

View File

@@ -1 +1 @@
import{k as V,ap as $,o as w,c as k,a as o,b as t,w as d,t as f,aq as N,m as B,r as i,d as r,ar as C,h as b}from"./index-BFjouPFU.js";import{_ as L}from"./_plugin-vue_export-helper-DlAUqK2U.js";const M={class:"page"},T={class:"page-header"},U={class:"header-actions"},I={class:"card"},q={class:"table-header"},E={class:"pagination-bar"},F={__name:"Logs",setup(H){const h=i([]),p=i(0),c=i(1),u=i(20),_=i(""),g=i(!1);V(()=>v());async function v(){g.value=!0;const l=await $({page:c.value,page_size:u.value,search:_.value});h.value=l.data.list,p.value=l.data.total,g.value=!1}function y(l){if(!l)return"-";const e=new Date(l);if(isNaN(e.getTime()))return l;const s=m=>String(m).padStart(2,"0");return`${e.getFullYear()}-${s(e.getMonth()+1)}-${s(e.getDate())} ${s(e.getHours())}:${s(e.getMinutes())}:${s(e.getSeconds())}`}return(l,e)=>{const s=r("el-input"),m=r("el-button"),n=r("el-table-column"),z=r("el-tag"),x=r("el-table"),D=r("el-pagination"),S=C("loading");return w(),k("div",M,[o("div",T,[e[4]||(e[4]=o("div",null,[o("div",{class:"page-title"},"操作日志"),o("div",{class:"page-subtitle"},"查看最近的系统操作记录")],-1)),o("div",U,[t(s,{modelValue:_.value,"onUpdate:modelValue":e[0]||(e[0]=a=>_.value=a),placeholder:"搜索操作内容",clearable:"",style:{width:"240px"}},null,8,["modelValue"]),t(m,{type:"primary",onClick:v},{default:d(()=>[...e[3]||(e[3]=[b("查询",-1)])]),_:1})])]),o("div",I,[o("div",q,"共 "+f(p.value)+" 条记录",1),N((w(),B(x,{data:h.value,stripe:"",style:{width:"100%"},class:"modern-table"},{default:d(()=>[t(n,{prop:"id",label:"ID",width:"70"}),t(n,{prop:"action",label:"操作",width:"140"}),t(n,{prop:"target_type",label:"对象",width:"100"},{default:d(({row:a})=>[t(z,{size:"small",effect:"plain",round:""},{default:d(()=>[b(f(a.target_type),1)]),_:2},1024)]),_:1}),t(n,{prop:"target_name",label:"对象名称","min-width":"160"}),t(n,{prop:"details",label:"详情","min-width":"240","show-overflow-tooltip":""}),t(n,{prop:"created_at",label:"时间",width:"170"},{default:d(({row:a})=>[b(f(y(a.created_at)),1)]),_:1})]),_:1},8,["data"])),[[S,g.value]]),o("div",E,[t(D,{"current-page":c.value,"onUpdate:currentPage":e[1]||(e[1]=a=>c.value=a),"page-size":u.value,"onUpdate:pageSize":e[2]||(e[2]=a=>u.value=a),"page-sizes":[10,20,50,100],layout:"total, sizes, prev, pager, next",total:p.value,onChange:v},null,8,["current-page","page-size","total"])])])])}}},j=L(F,[["__scopeId","data-v-b1b09e4f"]]);export{j as default};
import{k as V,ap as $,o as w,c as k,a as o,b as t,w as d,t as f,aq as N,m as B,r as i,d as r,ar as C,h as b}from"./index-lpjSKhQ-.js";import{_ as L}from"./_plugin-vue_export-helper-DlAUqK2U.js";const M={class:"page"},T={class:"page-header"},U={class:"header-actions"},I={class:"card"},q={class:"table-header"},E={class:"pagination-bar"},F={__name:"Logs",setup(H){const h=i([]),p=i(0),c=i(1),u=i(20),_=i(""),g=i(!1);V(()=>v());async function v(){g.value=!0;const l=await $({page:c.value,page_size:u.value,search:_.value});h.value=l.data.list,p.value=l.data.total,g.value=!1}function y(l){if(!l)return"-";const e=new Date(l);if(isNaN(e.getTime()))return l;const s=m=>String(m).padStart(2,"0");return`${e.getFullYear()}-${s(e.getMonth()+1)}-${s(e.getDate())} ${s(e.getHours())}:${s(e.getMinutes())}:${s(e.getSeconds())}`}return(l,e)=>{const s=r("el-input"),m=r("el-button"),n=r("el-table-column"),z=r("el-tag"),x=r("el-table"),D=r("el-pagination"),S=C("loading");return w(),k("div",M,[o("div",T,[e[4]||(e[4]=o("div",null,[o("div",{class:"page-title"},"操作日志"),o("div",{class:"page-subtitle"},"查看最近的系统操作记录")],-1)),o("div",U,[t(s,{modelValue:_.value,"onUpdate:modelValue":e[0]||(e[0]=a=>_.value=a),placeholder:"搜索操作内容",clearable:"",style:{width:"240px"}},null,8,["modelValue"]),t(m,{type:"primary",onClick:v},{default:d(()=>[...e[3]||(e[3]=[b("查询",-1)])]),_:1})])]),o("div",I,[o("div",q,"共 "+f(p.value)+" 条记录",1),N((w(),B(x,{data:h.value,stripe:"",style:{width:"100%"},class:"modern-table"},{default:d(()=>[t(n,{prop:"id",label:"ID",width:"70"}),t(n,{prop:"action",label:"操作",width:"140"}),t(n,{prop:"target_type",label:"对象",width:"100"},{default:d(({row:a})=>[t(z,{size:"small",effect:"plain",round:""},{default:d(()=>[b(f(a.target_type),1)]),_:2},1024)]),_:1}),t(n,{prop:"target_name",label:"对象名称","min-width":"160"}),t(n,{prop:"details",label:"详情","min-width":"240","show-overflow-tooltip":""}),t(n,{prop:"created_at",label:"时间",width:"170"},{default:d(({row:a})=>[b(f(y(a.created_at)),1)]),_:1})]),_:1},8,["data"])),[[S,g.value]]),o("div",E,[t(D,{"current-page":c.value,"onUpdate:currentPage":e[1]||(e[1]=a=>c.value=a),"page-size":u.value,"onUpdate:pageSize":e[2]||(e[2]=a=>u.value=a),"page-sizes":[10,20,50,100],layout:"total, sizes, prev, pager, next",total:p.value,onChange:v},null,8,["current-page","page-size","total"])])])])}}},j=L(F,[["__scopeId","data-v-b1b09e4f"]]);export{j as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
import{k as h,o as i,c as m,a as s,b as e,w as t,m as d,n as r,t as v,p as C,r as x,q as w,d as _,u as E,e as l,v as L,x as M,y as A,z as B,A as D,B as N,C as V,f as z,D as I,F as S,E as q,G as F,H as G}from"./index-BFjouPFU.js";import{_ as H}from"./_plugin-vue_export-helper-DlAUqK2U.js";const P={class:"layout"},R={key:0,class:"sidebar"},T={class:"nav"},$={class:"sidebar-footer"},j={class:"user-info"},J={class:"user-name"},K={class:"main-inner"},O={__name:"MainLayout",setup(Q){const f=E(),u=w(()=>F().is_admin),o=x(!1);h(()=>{o.value=document.documentElement.classList.contains("dark")});function p(){o.value=!o.value,document.documentElement.classList.toggle("dark",o.value),localStorage.setItem("theme",o.value?"dark":"light")}async function g(){try{await S()}catch{}G(),q.success("已退出"),f.push("/login")}return(k,a)=>{const n=_("el-icon"),c=_("router-link"),y=_("el-button"),b=_("router-view");return i(),m("div",P,[u.value?(i(),m("aside",R,[a[5]||(a[5]=s("div",{class:"brand"},[s("div",{class:"brand-logo"},"LM"),s("div",{class:"brand-text"},"LAN Manager")],-1)),s("nav",T,[e(c,{to:"/machines",class:"nav-item","active-class":"active"},{default:t(()=>[e(n,null,{default:t(()=>[e(l(L))]),_:1}),a[0]||(a[0]=s("span",null,"机器列表",-1))]),_:1}),u.value?(i(),d(c,{key:0,to:"/topology",class:"nav-item","active-class":"active"},{default:t(()=>[e(n,null,{default:t(()=>[e(l(M))]),_:1}),a[1]||(a[1]=s("span",null,"拓扑图",-1))]),_:1})):r("",!0),u.value?(i(),d(c,{key:1,to:"/logs",class:"nav-item","active-class":"active"},{default:t(()=>[e(n,null,{default:t(()=>[e(l(A))]),_:1}),a[2]||(a[2]=s("span",null,"操作日志",-1))]),_:1})):r("",!0),u.value?(i(),d(c,{key:2,to:"/pve-hosts",class:"nav-item","active-class":"active"},{default:t(()=>[e(n,null,{default:t(()=>[e(l(B))]),_:1}),a[3]||(a[3]=s("span",null,"PVE 主机",-1))]),_:1})):r("",!0)]),s("div",{class:"theme-toggle",onClick:p},[e(n,{class:"theme-icon"},{default:t(()=>[(i(),d(D(o.value?l(N):l(V))))]),_:1}),s("span",null,v(o.value?"浅色模式":"深色模式"),1)]),s("div",$,[s("div",j,[e(n,{class:"user-icon"},{default:t(()=>[e(l(z))]),_:1}),s("span",J,v(u.value?"管理员":"访客"),1)]),e(y,{text:"",class:"logout-btn",onClick:g},{default:t(()=>[e(n,null,{default:t(()=>[e(l(I))]),_:1}),a[4]||(a[4]=s("span",null,"退出",-1))]),_:1})])])):r("",!0),s("main",{class:C(["main",{"no-sidebar":!u.value}])},[s("div",K,[e(b)])],2)])}}},X=H(O,[["__scopeId","data-v-dac2493b"]]);export{X as default};
import{k as h,o as i,c as m,a as s,b as e,w as t,m as d,n as r,t as v,p as C,r as x,q as w,d as _,u as E,e as l,v as L,x as M,y as A,z as B,A as D,B as N,C as V,f as z,D as I,F as S,E as q,G as F,H as G}from"./index-lpjSKhQ-.js";import{_ as H}from"./_plugin-vue_export-helper-DlAUqK2U.js";const P={class:"layout"},R={key:0,class:"sidebar"},T={class:"nav"},$={class:"sidebar-footer"},j={class:"user-info"},J={class:"user-name"},K={class:"main-inner"},O={__name:"MainLayout",setup(Q){const f=E(),u=w(()=>F().is_admin),o=x(!1);h(()=>{o.value=document.documentElement.classList.contains("dark")});function p(){o.value=!o.value,document.documentElement.classList.toggle("dark",o.value),localStorage.setItem("theme",o.value?"dark":"light")}async function g(){try{await S()}catch{}G(),q.success("已退出"),f.push("/login")}return(k,a)=>{const n=_("el-icon"),c=_("router-link"),y=_("el-button"),b=_("router-view");return i(),m("div",P,[u.value?(i(),m("aside",R,[a[5]||(a[5]=s("div",{class:"brand"},[s("div",{class:"brand-logo"},"LM"),s("div",{class:"brand-text"},"LAN Manager")],-1)),s("nav",T,[e(c,{to:"/machines",class:"nav-item","active-class":"active"},{default:t(()=>[e(n,null,{default:t(()=>[e(l(L))]),_:1}),a[0]||(a[0]=s("span",null,"机器列表",-1))]),_:1}),u.value?(i(),d(c,{key:0,to:"/topology",class:"nav-item","active-class":"active"},{default:t(()=>[e(n,null,{default:t(()=>[e(l(M))]),_:1}),a[1]||(a[1]=s("span",null,"拓扑图",-1))]),_:1})):r("",!0),u.value?(i(),d(c,{key:1,to:"/logs",class:"nav-item","active-class":"active"},{default:t(()=>[e(n,null,{default:t(()=>[e(l(A))]),_:1}),a[2]||(a[2]=s("span",null,"操作日志",-1))]),_:1})):r("",!0),u.value?(i(),d(c,{key:2,to:"/pve-hosts",class:"nav-item","active-class":"active"},{default:t(()=>[e(n,null,{default:t(()=>[e(l(B))]),_:1}),a[3]||(a[3]=s("span",null,"PVE 主机",-1))]),_:1})):r("",!0)]),s("div",{class:"theme-toggle",onClick:p},[e(n,{class:"theme-icon"},{default:t(()=>[(i(),d(D(o.value?l(N):l(V))))]),_:1}),s("span",null,v(o.value?"浅色模式":"深色模式"),1)]),s("div",$,[s("div",j,[e(n,{class:"user-icon"},{default:t(()=>[e(l(z))]),_:1}),s("span",J,v(u.value?"管理员":"访客"),1)]),e(y,{text:"",class:"logout-btn",onClick:g},{default:t(()=>[e(n,null,{default:t(()=>[e(l(I))]),_:1}),a[4]||(a[4]=s("span",null,"退出",-1))]),_:1})])])):r("",!0),s("main",{class:C(["main",{"no-sidebar":!u.value}])},[s("div",K,[e(b)])],2)])}}},X=H(O,[["__scopeId","data-v-dac2493b"]]);export{X as default};

View File

@@ -1 +0,0 @@
.toolbar[data-v-c935d190]{display:flex;align-items:center;justify-content:space-between;margin-bottom:20px}.page-title[data-v-c935d190]{margin:0;font-size:20px;font-weight:600}.hosts-grid[data-v-c935d190]{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px}.host-card[data-v-c935d190]{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:16px}.host-header[data-v-c935d190]{display:flex;align-items:center;gap:10px;margin-bottom:12px}.host-icon[data-v-c935d190]{font-size:20px;color:var(--el-color-primary)}.host-name[data-v-c935d190]{font-size:16px;font-weight:600}.host-info[data-v-c935d190]{margin-bottom:12px}.info-row[data-v-c935d190]{display:flex;font-size:13px;margin-bottom:4px}.info-row .label[data-v-c935d190]{color:var(--text-secondary);width:50px}.info-row .value[data-v-c935d190]{color:var(--text)}.host-actions[data-v-c935d190]{display:flex;gap:8px}

1
web/dist/assets/PVEHosts-Bv16iTgA.css vendored Normal file
View File

@@ -0,0 +1 @@
.toolbar[data-v-bd0711be]{display:flex;align-items:center;justify-content:space-between;margin-bottom:20px}.page-title[data-v-bd0711be]{margin:0;font-size:20px;font-weight:600}.hosts-grid[data-v-bd0711be]{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px}.host-card[data-v-bd0711be]{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:16px}.host-header[data-v-bd0711be]{display:flex;align-items:center;gap:10px;margin-bottom:12px}.host-icon[data-v-bd0711be]{font-size:20px;color:var(--el-color-primary)}.host-name[data-v-bd0711be]{font-size:16px;font-weight:600}.host-info[data-v-bd0711be]{margin-bottom:12px}.info-row[data-v-bd0711be]{display:flex;font-size:13px;margin-bottom:4px}.info-row .label[data-v-bd0711be]{color:var(--text-secondary);width:50px}.info-row .value[data-v-bd0711be]{color:var(--text)}.host-actions[data-v-bd0711be]{display:flex;gap:8px}

View File

@@ -1 +0,0 @@
import{k as N,Q as $,o as m,c as f,a as t,b as s,w as o,e as b,M,m as S,n as k,N as z,O as D,r as y,d,h as p,v as L,t as c,a8 as F,as as I,E as V,at as O,au as Q}from"./index-BFjouPFU.js";import{_ as T}from"./_plugin-vue_export-helper-DlAUqK2U.js";const j={class:"page"},A={class:"toolbar"},G={key:1,class:"hosts-grid"},J={class:"host-header"},K={class:"host-name"},R={class:"host-info"},W={class:"info-row"},X={class:"value"},Y={class:"info-row"},Z={class:"value"},ee={class:"host-actions"},le={__name:"PVEHosts",setup(ae){const v=y([]),i=y(!1),l=y({name:"",hostname:"",port:8006,username:"",password:"",verify_ssl:!1});N(()=>{w()});async function w(){const n=await $();v.value=n.data}function g(n){l.value=n?{...n,password:""}:{name:"",hostname:"",port:8006,username:"",password:"",verify_ssl:!1},i.value=!0}async function E(){if(!l.value.name||!l.value.hostname||!l.value.username){V.warning("请填写必填项");return}if(!l.value.id&&!l.value.password){V.warning("请填写密码");return}try{l.value.id?await O(l.value.id,l.value):await Q(l.value),V.success("保存成功"),i.value=!1,w()}catch{}}async function C(n){try{await F.confirm(`确定要删除主机 "${n.name}" 吗?`,"确认删除",{type:"warning"}),await I(n.id),V.success("删除成功"),w()}catch{}}return(n,e)=>{const r=d("el-button"),x=d("el-empty"),P=d("el-icon"),_=d("el-input"),u=d("el-form-item"),H=d("el-input-number"),U=d("el-switch"),h=d("el-form"),q=d("el-dialog");return m(),f("div",j,[t("div",A,[e[10]||(e[10]=t("h2",{class:"page-title"},"PVE 主机管理",-1)),s(r,{type:"primary",icon:b(M),onClick:e[0]||(e[0]=a=>g())},{default:o(()=>[...e[9]||(e[9]=[p("添加主机",-1)])]),_:1},8,["icon"])]),v.value.length?k("",!0):(m(),S(x,{key:0,description:"暂无 PVE 主机"})),v.value.length?(m(),f("div",G,[(m(!0),f(z,null,D(v.value,a=>(m(),f("div",{key:a.id,class:"host-card"},[t("div",J,[s(P,{class:"host-icon"},{default:o(()=>[s(b(L))]),_:1}),t("span",K,c(a.name),1)]),t("div",R,[t("div",W,[e[11]||(e[11]=t("span",{class:"label"},"地址:",-1)),t("span",X,c(a.hostname)+":"+c(a.port),1)]),t("div",Y,[e[12]||(e[12]=t("span",{class:"label"},"用户:",-1)),t("span",Z,c(a.username),1)])]),t("div",ee,[s(r,{size:"small",onClick:B=>g(a)},{default:o(()=>[...e[13]||(e[13]=[p("编辑",-1)])]),_:1},8,["onClick"]),s(r,{size:"small",type:"danger",onClick:B=>C(a)},{default:o(()=>[...e[14]||(e[14]=[p("删除",-1)])]),_:1},8,["onClick"])])]))),128))])):k("",!0),s(q,{modelValue:i.value,"onUpdate:modelValue":e[8]||(e[8]=a=>i.value=a),title:l.value.id?"编辑主机":"添加主机",width:"480px",class:"modern-dialog","destroy-on-close":""},{footer:o(()=>[s(r,{onClick:e[7]||(e[7]=a=>i.value=!1)},{default:o(()=>[...e[15]||(e[15]=[p("取消",-1)])]),_:1}),s(r,{type:"primary",onClick:E},{default:o(()=>[...e[16]||(e[16]=[p("保存",-1)])]),_:1})]),default:o(()=>[s(h,{model:l.value,"label-width":"90px"},{default:o(()=>[s(u,{label:"名称",required:""},{default:o(()=>[s(_,{modelValue:l.value.name,"onUpdate:modelValue":e[1]||(e[1]=a=>l.value.name=a),placeholder:"如 PVE-01"},null,8,["modelValue"])]),_:1}),s(u,{label:"地址",required:""},{default:o(()=>[s(_,{modelValue:l.value.hostname,"onUpdate:modelValue":e[2]||(e[2]=a=>l.value.hostname=a),placeholder:"192.168.1.100"},null,8,["modelValue"])]),_:1}),s(u,{label:"端口"},{default:o(()=>[s(H,{modelValue:l.value.port,"onUpdate:modelValue":e[3]||(e[3]=a=>l.value.port=a),min:1,max:65535,style:{width:"100%"}},null,8,["modelValue"])]),_:1}),s(u,{label:"用户名",required:""},{default:o(()=>[s(_,{modelValue:l.value.username,"onUpdate:modelValue":e[4]||(e[4]=a=>l.value.username=a),placeholder:"root@pam 或 root@vmbr0"},null,8,["modelValue"])]),_:1}),s(u,{label:"密码",required:!l.value.id},{default:o(()=>[s(_,{modelValue:l.value.password,"onUpdate:modelValue":e[5]||(e[5]=a=>l.value.password=a),type:"password","show-password":"",placeholder:l.value.id?"留空保持不变":"必填"},null,8,["modelValue","placeholder"])]),_:1},8,["required"]),s(u,{label:"SSL 验证"},{default:o(()=>[s(U,{modelValue:l.value.verify_ssl,"onUpdate:modelValue":e[6]||(e[6]=a=>l.value.verify_ssl=a)},null,8,["modelValue"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue","title"])])}}},te=T(le,[["__scopeId","data-v-c935d190"]]);export{te as default};

1
web/dist/assets/PVEHosts-DgnxRMDp.js vendored Normal file
View File

@@ -0,0 +1 @@
import{k as N,Q as $,o as p,c as f,a as t,b as o,w as s,e as g,M,m as S,n as k,N as z,O as D,r as y,d,h as v,v as L,t as c,a8 as F,as as I,E as V,at as O,au as Q}from"./index-lpjSKhQ-.js";import{_ as T}from"./_plugin-vue_export-helper-DlAUqK2U.js";const j={class:"page"},A={class:"toolbar"},G={key:1,class:"hosts-grid"},J={class:"host-header"},K={class:"host-name"},R={class:"host-info"},W={class:"info-row"},X={class:"value"},Y={class:"info-row"},Z={class:"value"},ee={class:"host-actions"},le={__name:"PVEHosts",setup(ae){const _=y([]),i=y(!1),l=y({name:"",hostname:"",port:8006,node_name:"pve",username:"",password:"",verify_ssl:!1});N(()=>{w()});async function w(){const n=await $();_.value=n.data}function b(n){l.value=n?{...n,password:""}:{name:"",hostname:"",port:8006,node_name:"pve",username:"",password:"",verify_ssl:!1},i.value=!0}async function E(){if(!l.value.name||!l.value.hostname||!l.value.username){V.warning("请填写必填项");return}if(!l.value.id&&!l.value.password){V.warning("请填写密码");return}try{l.value.id?await O(l.value.id,l.value):await Q(l.value),V.success("保存成功"),i.value=!1,w()}catch{}}async function C(n){try{await F.confirm(`确定要删除主机 "${n.name}" 吗?`,"确认删除",{type:"warning"}),await I(n.id),V.success("删除成功"),w()}catch{}}return(n,e)=>{const r=d("el-button"),x=d("el-empty"),P=d("el-icon"),m=d("el-input"),u=d("el-form-item"),U=d("el-input-number"),H=d("el-switch"),h=d("el-form"),q=d("el-dialog");return p(),f("div",j,[t("div",A,[e[11]||(e[11]=t("h2",{class:"page-title"},"PVE 主机管理",-1)),o(r,{type:"primary",icon:g(M),onClick:e[0]||(e[0]=a=>b())},{default:s(()=>[...e[10]||(e[10]=[v("添加主机",-1)])]),_:1},8,["icon"])]),_.value.length?k("",!0):(p(),S(x,{key:0,description:"暂无 PVE 主机"})),_.value.length?(p(),f("div",G,[(p(!0),f(z,null,D(_.value,a=>(p(),f("div",{key:a.id,class:"host-card"},[t("div",J,[o(P,{class:"host-icon"},{default:s(()=>[o(g(L))]),_:1}),t("span",K,c(a.name),1)]),t("div",R,[t("div",W,[e[12]||(e[12]=t("span",{class:"label"},"地址:",-1)),t("span",X,c(a.hostname)+":"+c(a.port),1)]),t("div",Y,[e[13]||(e[13]=t("span",{class:"label"},"用户:",-1)),t("span",Z,c(a.username),1)])]),t("div",ee,[o(r,{size:"small",onClick:B=>b(a)},{default:s(()=>[...e[14]||(e[14]=[v("编辑",-1)])]),_:1},8,["onClick"]),o(r,{size:"small",type:"danger",onClick:B=>C(a)},{default:s(()=>[...e[15]||(e[15]=[v("删除",-1)])]),_:1},8,["onClick"])])]))),128))])):k("",!0),o(q,{modelValue:i.value,"onUpdate:modelValue":e[9]||(e[9]=a=>i.value=a),title:l.value.id?"编辑主机":"添加主机",width:"480px",class:"modern-dialog","destroy-on-close":""},{footer:s(()=>[o(r,{onClick:e[8]||(e[8]=a=>i.value=!1)},{default:s(()=>[...e[16]||(e[16]=[v("取消",-1)])]),_:1}),o(r,{type:"primary",onClick:E},{default:s(()=>[...e[17]||(e[17]=[v("保存",-1)])]),_:1})]),default:s(()=>[o(h,{model:l.value,"label-width":"90px"},{default:s(()=>[o(u,{label:"名称",required:""},{default:s(()=>[o(m,{modelValue:l.value.name,"onUpdate:modelValue":e[1]||(e[1]=a=>l.value.name=a),placeholder:"如 PVE-01"},null,8,["modelValue"])]),_:1}),o(u,{label:"地址",required:""},{default:s(()=>[o(m,{modelValue:l.value.hostname,"onUpdate:modelValue":e[2]||(e[2]=a=>l.value.hostname=a),placeholder:"192.168.1.100"},null,8,["modelValue"])]),_:1}),o(u,{label:"节点名"},{default:s(()=>[o(m,{modelValue:l.value.node_name,"onUpdate:modelValue":e[3]||(e[3]=a=>l.value.node_name=a),placeholder:"pve默认"},null,8,["modelValue"])]),_:1}),o(u,{label:"端口"},{default:s(()=>[o(U,{modelValue:l.value.port,"onUpdate:modelValue":e[4]||(e[4]=a=>l.value.port=a),min:1,max:65535,style:{width:"100%"}},null,8,["modelValue"])]),_:1}),o(u,{label:"用户名",required:""},{default:s(()=>[o(m,{modelValue:l.value.username,"onUpdate:modelValue":e[5]||(e[5]=a=>l.value.username=a),placeholder:"root@pam 或 root@vmbr0"},null,8,["modelValue"])]),_:1}),o(u,{label:"密码",required:!l.value.id},{default:s(()=>[o(m,{modelValue:l.value.password,"onUpdate:modelValue":e[6]||(e[6]=a=>l.value.password=a),type:"password","show-password":"",placeholder:l.value.id?"留空保持不变":"必填"},null,8,["modelValue","placeholder"])]),_:1},8,["required"]),o(u,{label:"SSL 验证"},{default:s(()=>[o(H,{modelValue:l.value.verify_ssl,"onUpdate:modelValue":e[7]||(e[7]=a=>l.value.verify_ssl=a)},null,8,["modelValue"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue","title"])])}}},te=T(le,[["__scopeId","data-v-bd0711be"]]);export{te as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
web/dist/index.html vendored
View File

@@ -5,7 +5,7 @@
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>局域网机器管理后台</title>
<script type="module" crossorigin src="/assets/index-BFjouPFU.js"></script>
<script type="module" crossorigin src="/assets/index-lpjSKhQ-.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DHYRt9JF.css">
</head>
<body>

View File

@@ -231,6 +231,15 @@
</el-form-item>
<el-form-item label="系统版本"><el-input v-model="editing.os_version" /></el-form-item>
<el-form-item label="备注"><el-input v-model="editing.notes" type="textarea" :rows="2" /></el-form-item>
<el-divider content-position="left">PVE 配置可选</el-divider>
<el-form-item label="PVE 主机">
<el-select v-model="editing.pve_host_id" placeholder="选择 PVE 主机" clearable style="width:100%">
<el-option v-for="h in pveHosts" :key="h.id" :label="h.name" :value="h.id" />
</el-select>
</el-form-item>
<el-form-item label="虚拟机 ID">
<el-input v-model="editing.pve_vmid" placeholder="如 101" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
@@ -308,7 +317,7 @@ import {
fetchMachine, updateMachine, deleteMachine,
fetchServices, createService, updateService, deleteService,
fetchRelationships, createRelationship, updateRelationship, deleteRelationship,
sshInfo, syncSSH, fetchMachines, fetchOfflineLogs,
sshInfo, syncSSH, fetchMachines, fetchOfflineLogs, fetchPVEHosts,
checkAuth, uiRefreshInterval,
startVM as apiStartVM, stopVM as apiStopVM, fetchVMStatus,
} from '@/api'
@@ -326,6 +335,7 @@ const relationships = ref([])
const vmLoading = ref(false)
const allMachines = ref([])
const offlineLogs = ref([])
const pveHosts = ref([])
const dialogVisible = ref(false)
const editing = ref({})
@@ -355,6 +365,10 @@ onMounted(async () => {
await loadRelationships()
const res = await fetchMachines()
allMachines.value = res.data
try {
const pveRes = await fetchPVEHosts()
pveHosts.value = pveRes.data
} catch (e) {}
}
await checkAuth()
const interval = uiRefreshInterval || 10000
@@ -415,7 +429,7 @@ async function loadRelationships() {
}
function openEdit(item) {
editing.value = { ...item, ssh_port: item.ssh_port || 22, ssh_username: item.ssh_username || '', ssh_password: '' }
editing.value = { ...item, ssh_port: item.ssh_port || 22, ssh_username: item.ssh_username || '', ssh_password: '', pve_host_id: item.pve_host_id || null, pve_vmid: item.pve_vmid || '' }
dialogVisible.value = true
}