fix(pve): 修复编译错误,确保前后端可编译通过
- services/pve.go: 导入 db 包,DB -> db.DB
- handlers/pve.go: 重写为 Gin 风格(原为标准库 net/http)
- go.mod/go.sum: go mod tidy 更新依赖
- web/dist: 重新构建前端包含 PVEHosts 页面
[金渐层/K2.6-code-preview🐾]
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -14,3 +14,6 @@ docs/SOP.md
|
|||||||
|
|
||||||
# System files
|
# System files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
web/node_modules/
|
||||||
|
|||||||
15
go.mod
15
go.mod
@@ -1,6 +1,14 @@
|
|||||||
module lan-manager
|
module lan-manager
|
||||||
|
|
||||||
go 1.21
|
go 1.25.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gin-contrib/sessions v1.1.0
|
||||||
|
github.com/gin-gonic/gin v1.12.0
|
||||||
|
golang.org/x/crypto v0.50.0
|
||||||
|
golang.org/x/net v0.53.0
|
||||||
|
modernc.org/sqlite v1.48.2
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||||
@@ -9,9 +17,7 @@ require (
|
|||||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
|
||||||
github.com/gin-contrib/sessions v1.1.0 // indirect
|
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
github.com/gin-gonic/gin v1.12.0 // indirect
|
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.30.1 // indirect
|
github.com/go-playground/validator/v10 v10.30.1 // indirect
|
||||||
@@ -36,13 +42,10 @@ require (
|
|||||||
github.com/ugorji/go/codec v1.3.1 // indirect
|
github.com/ugorji/go/codec v1.3.1 // indirect
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
|
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
|
||||||
golang.org/x/arch v0.22.0 // indirect
|
golang.org/x/arch v0.22.0 // indirect
|
||||||
golang.org/x/crypto v0.50.0 // indirect
|
|
||||||
golang.org/x/net v0.53.0 // indirect
|
|
||||||
golang.org/x/sys v0.43.0 // indirect
|
golang.org/x/sys v0.43.0 // indirect
|
||||||
golang.org/x/text v0.36.0 // indirect
|
golang.org/x/text v0.36.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.10 // indirect
|
google.golang.org/protobuf v1.36.10 // indirect
|
||||||
modernc.org/libc v1.70.0 // indirect
|
modernc.org/libc v1.70.0 // indirect
|
||||||
modernc.org/mathutil v1.7.1 // indirect
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
modernc.org/memory v1.11.0 // indirect
|
modernc.org/memory v1.11.0 // indirect
|
||||||
modernc.org/sqlite v1.48.2 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
46
go.sum
46
go.sum
@@ -7,6 +7,7 @@ github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCc
|
|||||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
@@ -18,6 +19,8 @@ github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w
|
|||||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||||
github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
|
github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
|
||||||
github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
|
github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
@@ -28,7 +31,13 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
|||||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||||
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||||
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
|
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
|
||||||
@@ -37,6 +46,8 @@ github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kX
|
|||||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||||
github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ=
|
github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ=
|
||||||
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
|
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||||
@@ -54,6 +65,7 @@ github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOF
|
|||||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||||
@@ -70,34 +82,66 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
|
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
|
||||||
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||||
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
|
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
|
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
|
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
|
||||||
|
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||||
|
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||||
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
|
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
|
||||||
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
||||||
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
||||||
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
||||||
|
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||||
|
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||||
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||||
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||||
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
|
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
|
||||||
|
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
|
||||||
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||||
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||||
|
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||||
|
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
||||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
|
||||||
|
modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||||
|
modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw=
|
||||||
|
modernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0=
|
||||||
|
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
|
||||||
|
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
|
||||||
|
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||||
|
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||||
|
modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=
|
||||||
|
modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||||
|
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||||
|
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||||
modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw=
|
modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw=
|
||||||
modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo=
|
modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo=
|
||||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||||
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||||
|
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||||
|
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||||
|
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||||
|
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||||
modernc.org/sqlite v1.48.2 h1:5CnW4uP8joZtA0LedVqLbZV5GD7F/0x91AXeSyjoh5c=
|
modernc.org/sqlite v1.48.2 h1:5CnW4uP8joZtA0LedVqLbZV5GD7F/0x91AXeSyjoh5c=
|
||||||
modernc.org/sqlite v1.48.2/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
|
modernc.org/sqlite v1.48.2/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
|
||||||
|
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||||
|
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||||
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
"lan-manager/server/db"
|
"lan-manager/server/db"
|
||||||
"lan-manager/server/middleware"
|
"lan-manager/server/middleware"
|
||||||
"lan-manager/server/models"
|
"lan-manager/server/models"
|
||||||
@@ -23,15 +23,15 @@ func NewPVEHandler() *PVEHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List 获取 PVE 主机列表
|
// List 获取 PVE 主机列表
|
||||||
func (h *PVEHandler) List(w http.ResponseWriter, r *http.Request) {
|
func (h *PVEHandler) List(c *gin.Context) {
|
||||||
if !middleware.IsAdmin(r) {
|
if !middleware.IsAdmin(c) {
|
||||||
http.Error(w, "admin only", http.StatusForbidden)
|
c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hosts, err := h.service.GetAll()
|
hosts, err := h.service.GetAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,51 +40,51 @@ func (h *PVEHandler) List(w http.ResponseWriter, r *http.Request) {
|
|||||||
hosts[i].PasswordEnc = ""
|
hosts[i].PasswordEnc = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
middleware.JSON(w, hosts)
|
c.JSON(http.StatusOK, hosts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 获取单个 PVE 主机
|
// Get 获取单个 PVE 主机
|
||||||
func (h *PVEHandler) Get(w http.ResponseWriter, r *http.Request) {
|
func (h *PVEHandler) Get(c *gin.Context) {
|
||||||
if !middleware.IsAdmin(r) {
|
if !middleware.IsAdmin(c) {
|
||||||
http.Error(w, "admin only", http.StatusForbidden)
|
c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "invalid id", http.StatusBadRequest)
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
host, err := h.service.GetByID(id)
|
host, err := h.service.GetByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
http.Error(w, "not found", http.StatusNotFound)
|
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
host.PasswordEnc = ""
|
host.PasswordEnc = ""
|
||||||
middleware.JSON(w, host)
|
c.JSON(http.StatusOK, host)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create 创建 PVE 主机
|
// Create 创建 PVE 主机
|
||||||
func (h *PVEHandler) Create(w http.ResponseWriter, r *http.Request) {
|
func (h *PVEHandler) Create(c *gin.Context) {
|
||||||
if !middleware.IsAdmin(r) {
|
if !middleware.IsAdmin(c) {
|
||||||
http.Error(w, "admin only", http.StatusForbidden)
|
c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var host models.PVEHost
|
var host models.PVEHost
|
||||||
if err := json.NewDecoder(r.Body).Decode(&host); err != nil {
|
if err := c.ShouldBindJSON(&host); err != nil {
|
||||||
http.Error(w, "invalid request", http.StatusBadRequest)
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if host.Name == "" || host.Hostname == "" || host.Username == "" || host.Password == "" {
|
if host.Name == "" || host.Hostname == "" || host.Username == "" || host.Password == "" {
|
||||||
http.Error(w, "missing required fields", http.StatusBadRequest)
|
c.JSON(http.StatusBadRequest, gin.H{"error": "missing required fields"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,30 +93,30 @@ func (h *PVEHandler) Create(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := h.service.Create(&host); err != nil {
|
if err := h.service.Create(&host); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
host.PasswordEnc = ""
|
host.PasswordEnc = ""
|
||||||
middleware.JSON(w, host)
|
c.JSON(http.StatusCreated, host)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update 更新 PVE 主机
|
// Update 更新 PVE 主机
|
||||||
func (h *PVEHandler) Update(w http.ResponseWriter, r *http.Request) {
|
func (h *PVEHandler) Update(c *gin.Context) {
|
||||||
if !middleware.IsAdmin(r) {
|
if !middleware.IsAdmin(c) {
|
||||||
http.Error(w, "admin only", http.StatusForbidden)
|
c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "invalid id", http.StatusBadRequest)
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var host models.PVEHost
|
var host models.PVEHost
|
||||||
if err := json.NewDecoder(r.Body).Decode(&host); err != nil {
|
if err := c.ShouldBindJSON(&host); err != nil {
|
||||||
http.Error(w, "invalid request", http.StatusBadRequest)
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,52 +126,52 @@ func (h *PVEHandler) Update(w http.ResponseWriter, r *http.Request) {
|
|||||||
if host.Password == "" {
|
if host.Password == "" {
|
||||||
existing, err := h.service.GetByID(id)
|
existing, err := h.service.GetByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
host.PasswordEnc = existing.PasswordEnc
|
host.PasswordEnc = existing.PasswordEnc
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.service.Update(&host); err != nil {
|
if err := h.service.Update(&host); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
host.PasswordEnc = ""
|
host.PasswordEnc = ""
|
||||||
middleware.JSON(w, host)
|
c.JSON(http.StatusOK, host)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 删除 PVE 主机
|
// Delete 删除 PVE 主机
|
||||||
func (h *PVEHandler) Delete(w http.ResponseWriter, r *http.Request) {
|
func (h *PVEHandler) Delete(c *gin.Context) {
|
||||||
if !middleware.IsAdmin(r) {
|
if !middleware.IsAdmin(c) {
|
||||||
http.Error(w, "admin only", http.StatusForbidden)
|
c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "invalid id", http.StatusBadRequest)
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.service.Delete(id); err != nil {
|
if err := h.service.Delete(id); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
middleware.JSON(w, map[string]string{"message": "deleted"})
|
c.JSON(http.StatusOK, gin.H{"message": "deleted"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// VMStatus 获取虚拟机状态
|
// VMStatus 获取虚拟机状态
|
||||||
func (h *PVEHandler) VMStatus(w http.ResponseWriter, r *http.Request) {
|
func (h *PVEHandler) VMStatus(c *gin.Context) {
|
||||||
if !middleware.IsAdmin(r) {
|
if !middleware.IsAdmin(c) {
|
||||||
http.Error(w, "admin only", http.StatusForbidden)
|
c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
machineID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
machineID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "invalid id", http.StatusBadRequest)
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,34 +179,34 @@ func (h *PVEHandler) VMStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
var pveVMID sql.NullString
|
var pveVMID sql.NullString
|
||||||
err = db.DB.QueryRow(`SELECT pve_host_id, pve_vmid FROM machines WHERE id = ?`, machineID).Scan(&pveHostID, &pveVMID)
|
err = db.DB.QueryRow(`SELECT pve_host_id, pve_vmid FROM machines WHERE id = ?`, machineID).Scan(&pveHostID, &pveVMID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "machine not found", http.StatusNotFound)
|
c.JSON(http.StatusNotFound, gin.H{"error": "machine not found"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if pveHostID == nil || !pveVMID.Valid || pveVMID.String == "" {
|
if pveHostID == nil || !pveVMID.Valid || pveVMID.String == "" {
|
||||||
http.Error(w, "machine not linked to PVE VM", http.StatusBadRequest)
|
c.JSON(http.StatusBadRequest, gin.H{"error": "machine not linked to PVE VM"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
status, err := h.service.GetVMStatus(*pveHostID, pveVMID.String)
|
status, err := h.service.GetVMStatus(*pveHostID, pveVMID.String)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
middleware.JSON(w, status)
|
c.JSON(http.StatusOK, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VMStart 启动虚拟机
|
// VMStart 启动虚拟机
|
||||||
func (h *PVEHandler) VMStart(w http.ResponseWriter, r *http.Request) {
|
func (h *PVEHandler) VMStart(c *gin.Context) {
|
||||||
if !middleware.IsAdmin(r) {
|
if !middleware.IsAdmin(c) {
|
||||||
http.Error(w, "admin only", http.StatusForbidden)
|
c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
machineID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
machineID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "invalid id", http.StatusBadRequest)
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,33 +214,33 @@ func (h *PVEHandler) VMStart(w http.ResponseWriter, r *http.Request) {
|
|||||||
var pveVMID sql.NullString
|
var pveVMID sql.NullString
|
||||||
err = db.DB.QueryRow(`SELECT pve_host_id, pve_vmid FROM machines WHERE id = ?`, machineID).Scan(&pveHostID, &pveVMID)
|
err = db.DB.QueryRow(`SELECT pve_host_id, pve_vmid FROM machines WHERE id = ?`, machineID).Scan(&pveHostID, &pveVMID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "machine not found", http.StatusNotFound)
|
c.JSON(http.StatusNotFound, gin.H{"error": "machine not found"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if pveHostID == nil || !pveVMID.Valid || pveVMID.String == "" {
|
if pveHostID == nil || !pveVMID.Valid || pveVMID.String == "" {
|
||||||
http.Error(w, "machine not linked to PVE VM", http.StatusBadRequest)
|
c.JSON(http.StatusBadRequest, gin.H{"error": "machine not linked to PVE VM"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.service.StartVM(*pveHostID, pveVMID.String); err != nil {
|
if err := h.service.StartVM(*pveHostID, pveVMID.String); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
middleware.JSON(w, map[string]string{"message": "started"})
|
c.JSON(http.StatusOK, gin.H{"message": "started"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// VMStop 停止虚拟机
|
// VMStop 停止虚拟机
|
||||||
func (h *PVEHandler) VMStop(w http.ResponseWriter, r *http.Request) {
|
func (h *PVEHandler) VMStop(c *gin.Context) {
|
||||||
if !middleware.IsAdmin(r) {
|
if !middleware.IsAdmin(c) {
|
||||||
http.Error(w, "admin only", http.StatusForbidden)
|
c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
machineID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
machineID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "invalid id", http.StatusBadRequest)
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,19 +248,19 @@ func (h *PVEHandler) VMStop(w http.ResponseWriter, r *http.Request) {
|
|||||||
var pveVMID sql.NullString
|
var pveVMID sql.NullString
|
||||||
err = db.DB.QueryRow(`SELECT pve_host_id, pve_vmid FROM machines WHERE id = ?`, machineID).Scan(&pveHostID, &pveVMID)
|
err = db.DB.QueryRow(`SELECT pve_host_id, pve_vmid FROM machines WHERE id = ?`, machineID).Scan(&pveHostID, &pveVMID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "machine not found", http.StatusNotFound)
|
c.JSON(http.StatusNotFound, gin.H{"error": "machine not found"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if pveHostID == nil || !pveVMID.Valid || pveVMID.String == "" {
|
if pveHostID == nil || !pveVMID.Valid || pveVMID.String == "" {
|
||||||
http.Error(w, "machine not linked to PVE VM", http.StatusBadRequest)
|
c.JSON(http.StatusBadRequest, gin.H{"error": "machine not linked to PVE VM"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.service.StopVM(*pveHostID, pveVMID.String); err != nil {
|
if err := h.service.StopVM(*pveHostID, pveVMID.String); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
middleware.JSON(w, map[string]string{"message": "stopped"})
|
c.JSON(http.StatusOK, gin.H{"message": "stopped"})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"lan-manager/server/db"
|
||||||
"lan-manager/server/models"
|
"lan-manager/server/models"
|
||||||
"lan-manager/server/utils"
|
"lan-manager/server/utils"
|
||||||
)
|
)
|
||||||
@@ -282,7 +283,7 @@ func NewPVEHostService() *PVEHostService {
|
|||||||
|
|
||||||
// GetAll 获取所有 PVE 主机
|
// GetAll 获取所有 PVE 主机
|
||||||
func (s *PVEHostService) GetAll() ([]models.PVEHost, error) {
|
func (s *PVEHostService) GetAll() ([]models.PVEHost, error) {
|
||||||
rows, err := DB.Query(`SELECT id, name, hostname, port, username, password_enc, verify_ssl, created_at, updated_at FROM pve_hosts ORDER BY id`)
|
rows, err := db.DB.Query(`SELECT id, name, hostname, port, username, password_enc, verify_ssl, created_at, updated_at FROM pve_hosts ORDER BY id`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -305,7 +306,7 @@ func (s *PVEHostService) GetAll() ([]models.PVEHost, error) {
|
|||||||
func (s *PVEHostService) GetByID(id int64) (*models.PVEHost, error) {
|
func (s *PVEHostService) GetByID(id int64) (*models.PVEHost, error) {
|
||||||
var h models.PVEHost
|
var h models.PVEHost
|
||||||
var verifySSL int
|
var verifySSL int
|
||||||
err := DB.QueryRow(`SELECT id, name, hostname, port, username, password_enc, verify_ssl, created_at, updated_at FROM pve_hosts WHERE id = ?`, id).
|
err := db.DB.QueryRow(`SELECT id, name, hostname, port, username, 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.PasswordEnc, &verifySSL, &h.CreatedAt, &h.UpdatedAt)
|
Scan(&h.ID, &h.Name, &h.Hostname, &h.Port, &h.Username, &h.PasswordEnc, &verifySSL, &h.CreatedAt, &h.UpdatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -322,7 +323,7 @@ func (s *PVEHostService) Create(host *models.PVEHost) error {
|
|||||||
return fmt.Errorf("encrypt password failed: %w", err)
|
return fmt.Errorf("encrypt password failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := DB.Exec(`INSERT INTO pve_hosts (name, hostname, port, username, password_enc, verify_ssl) VALUES (?, ?, ?, ?, ?, ?)`,
|
result, err := db.DB.Exec(`INSERT INTO pve_hosts (name, hostname, port, username, password_enc, verify_ssl) VALUES (?, ?, ?, ?, ?, ?)`,
|
||||||
host.Name, host.Hostname, host.Port, host.Username, encPassword, boolToInt(host.VerifySSL))
|
host.Name, host.Hostname, host.Port, host.Username, encPassword, boolToInt(host.VerifySSL))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -344,12 +345,12 @@ func (s *PVEHostService) Update(host *models.PVEHost) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("encrypt password failed: %w", err)
|
return fmt.Errorf("encrypt password failed: %w", err)
|
||||||
}
|
}
|
||||||
_, err = DB.Exec(`UPDATE pve_hosts SET name=?, hostname=?, port=?, username=?, password_enc=?, verify_ssl=?, updated_at=CURRENT_TIMESTAMP WHERE id=?`,
|
_, err = db.DB.Exec(`UPDATE pve_hosts SET name=?, hostname=?, port=?, username=?, password_enc=?, verify_ssl=?, updated_at=CURRENT_TIMESTAMP WHERE id=?`,
|
||||||
host.Name, host.Hostname, host.Port, host.Username, encPassword, boolToInt(host.VerifySSL), host.ID)
|
host.Name, host.Hostname, host.Port, host.Username, encPassword, boolToInt(host.VerifySSL), host.ID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := DB.Exec(`UPDATE pve_hosts SET name=?, hostname=?, port=?, username=?, verify_ssl=?, updated_at=CURRENT_TIMESTAMP WHERE id=?`,
|
_, err := db.DB.Exec(`UPDATE pve_hosts SET name=?, hostname=?, port=?, username=?, verify_ssl=?, updated_at=CURRENT_TIMESTAMP WHERE id=?`,
|
||||||
host.Name, host.Hostname, host.Port, host.Username, boolToInt(host.VerifySSL), host.ID)
|
host.Name, host.Hostname, host.Port, host.Username, boolToInt(host.VerifySSL), host.ID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -357,10 +358,10 @@ func (s *PVEHostService) Update(host *models.PVEHost) error {
|
|||||||
// Delete 删除 PVE 主机
|
// Delete 删除 PVE 主机
|
||||||
func (s *PVEHostService) Delete(id int64) error {
|
func (s *PVEHostService) Delete(id int64) error {
|
||||||
// 先清除关联机器的 PVE 字段
|
// 先清除关联机器的 PVE 字段
|
||||||
if _, err := DB.Exec(`UPDATE machines SET pve_host_id = NULL, pve_vmid = NULL WHERE pve_host_id = ?`, id); err != nil {
|
if _, err := db.DB.Exec(`UPDATE machines SET pve_host_id = NULL, pve_vmid = NULL WHERE pve_host_id = ?`, id); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err := DB.Exec(`DELETE FROM pve_hosts WHERE id = ?`, id)
|
_, err := db.DB.Exec(`DELETE FROM pve_hosts WHERE id = ?`, id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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-Chagxl0Z.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-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};
|
||||||
1
web/dist/assets/Login-CyUiDLKS.js
vendored
1
web/dist/assets/Login-CyUiDLKS.js
vendored
@@ -1 +0,0 @@
|
|||||||
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-C_uWT3cF.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};
|
|
||||||
1
web/dist/assets/Logs-D4rB2TEm.js
vendored
1
web/dist/assets/Logs-D4rB2TEm.js
vendored
@@ -1 +0,0 @@
|
|||||||
import{k as S,ak as V,o as w,c as $,a as o,b as t,w as d,t as f,al as N,m as B,r as i,d as r,am as C,h as b}from"./index-C_uWT3cF.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"},E={class:"table-header"},F={class:"pagination-bar"},H={__name:"Logs",setup(P){const h=i([]),p=i(0),c=i(1),u=i(20),_=i(""),g=i(!1);S(()=>v());async function v(){g.value=!0;const l=await V({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"),k=r("el-pagination"),D=C("loading");return w(),$("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",E,"共 "+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"])),[[D,g.value]]),o("div",F,[t(k,{"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"])])])])}}},q=L(H,[["__scopeId","data-v-b1b09e4f"]]);export{q as default};
|
|
||||||
@@ -1 +1 @@
|
|||||||
import{k as S,aj as V,o as w,c as $,a as o,b as t,w as d,t as f,ak as N,m as B,r as i,d as r,al as C,h as b}from"./index-Chagxl0Z.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"},j={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);S(()=>v());async function v(){g.value=!0;const l=await V({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"),k=r("el-pagination"),D=C("loading");return w(),$("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",j,"共 "+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"])),[[D,g.value]]),o("div",E,[t(k,{"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"])])])])}}},q=L(F,[["__scopeId","data-v-b1b09e4f"]]);export{q 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-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};
|
||||||
1
web/dist/assets/MachineDetail-BRKIzc2h.css
vendored
Normal file
1
web/dist/assets/MachineDetail-BRKIzc2h.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
web/dist/assets/MachineDetail-Du94nURq.js
vendored
1
web/dist/assets/MachineDetail-Du94nURq.js
vendored
File diff suppressed because one or more lines are too long
1
web/dist/assets/MachineDetail-EJEjie9p.js
vendored
1
web/dist/assets/MachineDetail-EJEjie9p.js
vendored
File diff suppressed because one or more lines are too long
1
web/dist/assets/MachineDetail-OXzzIeiz.css
vendored
1
web/dist/assets/MachineDetail-OXzzIeiz.css
vendored
File diff suppressed because one or more lines are too long
1
web/dist/assets/MachineDetail-PZRasqha.js
vendored
Normal file
1
web/dist/assets/MachineDetail-PZRasqha.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
web/dist/assets/MachineDetail-dlU7SJns.css
vendored
1
web/dist/assets/MachineDetail-dlU7SJns.css
vendored
File diff suppressed because one or more lines are too long
1
web/dist/assets/MachineList-9XRtZKRa.css
vendored
Normal file
1
web/dist/assets/MachineList-9XRtZKRa.css
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.toolbar[data-v-cae8dc77]{display:flex;align-items:center;gap:12px;margin-bottom:20px}.search-wrap[data-v-cae8dc77]{position:relative;flex:1;max-width:360px}.search-wrap[data-v-cae8dc77] .el-input__wrapper{padding-left:34px;border-radius:10px;box-shadow:0 0 0 1px var(--border) inset}.search-icon[data-v-cae8dc77]{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:var(--text-muted);font-size:16px;z-index:1}.os-select[data-v-cae8dc77] .el-input__wrapper{border-radius:10px;box-shadow:0 0 0 1px var(--border) inset}.cards-grid[data-v-cae8dc77]{display:grid;grid-template-columns:repeat(2,1fr);gap:16px}@media (max-width: 900px){.cards-grid[data-v-cae8dc77]{grid-template-columns:1fr}}.server-card[data-v-cae8dc77]{background:var(--surface);border-radius:var(--radius);padding:18px;box-shadow:var(--shadow);border:1px solid var(--border);border-top-width:3px;border-top-color:var(--border-strong);cursor:pointer;transition:transform .12s ease,box-shadow .2s ease,opacity .2s ease,border-color .2s ease}.server-card[data-v-cae8dc77]:hover{transform:translateY(-2px);box-shadow:var(--shadow-lg);border-color:var(--border-strong)}.server-card.guest-card[data-v-cae8dc77]{cursor:default}.server-card.guest-card[data-v-cae8dc77]:hover{transform:none;box-shadow:var(--shadow);border-color:var(--border)}.server-card.offline-card[data-v-cae8dc77]{opacity:.65;border-top-color:var(--border)}.server-card.offline-card .hostname[data-v-cae8dc77]{color:var(--text-muted)}.card-header[data-v-cae8dc77]{display:flex;flex-direction:column;gap:6px}.title-row[data-v-cae8dc77]{display:flex;align-items:center;gap:10px}.os-dot[data-v-cae8dc77]{width:10px;height:10px;border-radius:50%;flex-shrink:0;box-shadow:inset 0 0 0 1px #00000014}.os-dot.os-linux[data-v-cae8dc77]{background:#3b82f6}.os-dot.os-windows[data-v-cae8dc77]{background:#22c55e}.os-dot.os-macos[data-v-cae8dc77]{background:#a855f7}.os-dot.os-other[data-v-cae8dc77]{background:#64748b}.status-badge[data-v-cae8dc77]{font-size:11px;padding:2px 8px;border-radius:999px;font-weight:600;line-height:1}.status-badge.online[data-v-cae8dc77]{background:#22c55e1f;color:#15803d}.status-badge.offline[data-v-cae8dc77]{background:#ef44441a;color:#b91c1c}html.dark .status-badge.online[data-v-cae8dc77]{background:#34d39926;color:#34d399}html.dark .status-badge.offline[data-v-cae8dc77]{background:#f8717126;color:#f87171}.hostname[data-v-cae8dc77]{font-weight:700;font-size:15px;color:var(--text)}.svc-tag[data-v-cae8dc77]{font-size:11px;height:18px;padding:0 8px;color:var(--text-secondary);border-color:var(--border)}.meta-row[data-v-cae8dc77]{display:flex;align-items:center;flex-wrap:wrap;gap:6px 0;font-size:12px;color:var(--text-secondary)}.meta-ip[data-v-cae8dc77]{color:var(--text);font-weight:500;background:var(--surface-hover);border:1px solid var(--border);padding:1px 6px;border-radius:4px}.meta-item+.meta-item[data-v-cae8dc77]:before,.meta-uptime[data-v-cae8dc77]:before{content:"·";margin:0 6px;color:var(--text-muted)}.meta-uptime[data-v-cae8dc77]{color:var(--success)}.stats-row[data-v-cae8dc77]{margin-top:14px;display:grid;grid-template-columns:repeat(3,1fr);gap:10px}.stat-pill[data-v-cae8dc77]{background:var(--pill-bg);border:1px solid var(--pill-border);border-radius:10px;padding:9px 10px;color:var(--pill-text);display:flex;align-items:center;gap:8px;transition:background .2s ease,border-color .2s ease}.pill-icon[data-v-cae8dc77]{width:22px;height:22px;border-radius:5px;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;background:#ffffff1a;flex-shrink:0}.pill-icon.cpu[data-v-cae8dc77]{color:#7dd3fc}.pill-icon.mem[data-v-cae8dc77]{color:#86efac}.pill-icon.disk[data-v-cae8dc77]{color:#93c5fd}.pill-body[data-v-cae8dc77]{flex:1;display:flex;flex-direction:column;gap:4px;min-width:0}.pill-label[data-v-cae8dc77]{font-size:10px;color:#ffffffd9;font-weight:600}.pill-bar[data-v-cae8dc77]{height:3px;background:#ffffff26;border-radius:2px;overflow:hidden}.pill-fill[data-v-cae8dc77]{height:100%;border-radius:2px;background:#ffffffe6;transition:width .3s ease}.pill-value[data-v-cae8dc77]{font-size:11px;font-weight:700;color:#fff;white-space:nowrap}.ports-row[data-v-cae8dc77]{margin-top:12px;display:flex;flex-wrap:wrap;gap:6px}.port-tag[data-v-cae8dc77]{font-size:11px;height:20px;padding:0 8px;color:var(--text-secondary);border-color:var(--border)}.more-ports[data-v-cae8dc77]{font-size:11px;color:var(--text-muted);line-height:20px}.sync-time[data-v-cae8dc77]{margin-top:10px;font-size:11px;color:var(--text-muted)}
|
||||||
1
web/dist/assets/MachineList-B0yEQVq5.js
vendored
1
web/dist/assets/MachineList-B0yEQVq5.js
vendored
File diff suppressed because one or more lines are too long
1
web/dist/assets/MachineList-Dl6ycQW2.js
vendored
Normal file
1
web/dist/assets/MachineList-Dl6ycQW2.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
web/dist/assets/MachineList-DpVAPZyx.css
vendored
1
web/dist/assets/MachineList-DpVAPZyx.css
vendored
File diff suppressed because one or more lines are too long
1
web/dist/assets/MachineList-xoH6VyjV.js
vendored
1
web/dist/assets/MachineList-xoH6VyjV.js
vendored
File diff suppressed because one or more lines are too long
1
web/dist/assets/MainLayout-BzeQKWOs.js
vendored
1
web/dist/assets/MainLayout-BzeQKWOs.js
vendored
@@ -1 +0,0 @@
|
|||||||
import{k as h,o as c,c as m,a as s,b as e,w as t,m as d,n as _,t as v,p as C,r as x,q as w,d as i,u as L,e as n,v as M,x as A,y as B,z as E,A as D,B as N,f as V,C as z,D as I,E as S,F as q,G as F}from"./index-Chagxl0Z.js";import{_ as G}from"./_plugin-vue_export-helper-DlAUqK2U.js";const R={class:"layout"},T={key:0,class:"sidebar"},$={class:"nav"},j={class:"sidebar-footer"},H={class:"user-info"},J={class:"user-name"},K={class:"main-inner"},O={__name:"MainLayout",setup(P){const f=L(),u=w(()=>q().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 I()}catch{}F(),S.success("已退出"),f.push("/login")}return(k,a)=>{const l=i("el-icon"),r=i("router-link"),y=i("el-button"),b=i("router-view");return c(),m("div",R,[u.value?(c(),m("aside",T,[a[4]||(a[4]=s("div",{class:"brand"},[s("div",{class:"brand-logo"},"LM"),s("div",{class:"brand-text"},"LAN Manager")],-1)),s("nav",$,[e(r,{to:"/machines",class:"nav-item","active-class":"active"},{default:t(()=>[e(l,null,{default:t(()=>[e(n(M))]),_:1}),a[0]||(a[0]=s("span",null,"机器列表",-1))]),_:1}),u.value?(c(),d(r,{key:0,to:"/topology",class:"nav-item","active-class":"active"},{default:t(()=>[e(l,null,{default:t(()=>[e(n(A))]),_:1}),a[1]||(a[1]=s("span",null,"拓扑图",-1))]),_:1})):_("",!0),u.value?(c(),d(r,{key:1,to:"/logs",class:"nav-item","active-class":"active"},{default:t(()=>[e(l,null,{default:t(()=>[e(n(B))]),_:1}),a[2]||(a[2]=s("span",null,"操作日志",-1))]),_:1})):_("",!0)]),s("div",{class:"theme-toggle",onClick:p},[e(l,{class:"theme-icon"},{default:t(()=>[(c(),d(E(o.value?n(D):n(N))))]),_:1}),s("span",null,v(o.value?"浅色模式":"深色模式"),1)]),s("div",j,[s("div",H,[e(l,{class:"user-icon"},{default:t(()=>[e(n(V))]),_:1}),s("span",J,v(u.value?"管理员":"访客"),1)]),e(y,{text:"",class:"logout-btn",onClick:g},{default:t(()=>[e(l,null,{default:t(()=>[e(n(z))]),_:1}),a[3]||(a[3]=s("span",null,"退出",-1))]),_:1})])])):_("",!0),s("main",{class:C(["main",{"no-sidebar":!u.value}])},[s("div",K,[e(b)])],2)])}}},W=G(O,[["__scopeId","data-v-a4c6174b"]]);export{W as default};
|
|
||||||
1
web/dist/assets/MainLayout-CJz-pM3g.css
vendored
1
web/dist/assets/MainLayout-CJz-pM3g.css
vendored
@@ -1 +0,0 @@
|
|||||||
.layout[data-v-a4c6174b]{display:flex;min-height:100vh}.sidebar[data-v-a4c6174b]{width:220px;background:#0f172a;color:#fff;display:flex;flex-direction:column;position:fixed;left:0;top:0;bottom:0;z-index:100}.brand[data-v-a4c6174b]{padding:22px 18px 14px;display:flex;align-items:center;gap:10px;border-bottom:1px solid rgba(255,255,255,.06)}.brand-logo[data-v-a4c6174b]{width:32px;height:32px;border-radius:8px;background:linear-gradient(135deg,#3b82f6,#60a5fa);display:flex;align-items:center;justify-content:center;font-weight:800;font-size:13px}.brand-text[data-v-a4c6174b]{font-weight:700;font-size:14px;letter-spacing:.3px}.nav[data-v-a4c6174b]{flex:1;padding:12px 10px;display:flex;flex-direction:column;gap:4px}.nav-item[data-v-a4c6174b]{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;color:#ffffffa6;text-decoration:none;font-size:13px;transition:background .15s ease,color .15s ease}.nav-item[data-v-a4c6174b]:hover{background:#ffffff0f;color:#ffffffe6}.nav-item.active[data-v-a4c6174b]{background:#3b82f62e;color:#60a5fa;font-weight:600}.nav-item .el-icon[data-v-a4c6174b]{font-size:16px}.sidebar-footer[data-v-a4c6174b]{padding:12px 10px 16px;border-top:1px solid rgba(255,255,255,.06);display:flex;flex-direction:column;gap:6px}.user-info[data-v-a4c6174b]{display:flex;align-items:center;gap:8px;padding:8px 10px;font-size:12px;color:#ffffff8c}.user-icon[data-v-a4c6174b]{font-size:14px}.user-name[data-v-a4c6174b]{font-weight:500;color:#ffffffd9}.logout-btn[data-v-a4c6174b]{justify-content:flex-start;width:100%;color:#ffffff8c;padding:8px 10px;border-radius:8px}.logout-btn[data-v-a4c6174b]:hover{color:#fff;background:#ffffff0f}.logout-btn span[data-v-a4c6174b]{margin-left:8px;font-size:12px}.main[data-v-a4c6174b]{flex:1;margin-left:220px;min-height:100vh;background:var(--bg)}.main-inner[data-v-a4c6174b]{padding:10px}.theme-toggle[data-v-a4c6174b]{margin:0 10px 10px;display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;color:#ffffff8c;font-size:13px;cursor:pointer;transition:background .15s ease,color .15s ease}.theme-toggle[data-v-a4c6174b]:hover{background:#ffffff0f;color:#ffffffe6}.theme-icon[data-v-a4c6174b]{font-size:16px}.main.no-sidebar[data-v-a4c6174b]{margin-left:0}@media (max-width: 768px){.sidebar[data-v-a4c6174b]{width:64px}.brand-text[data-v-a4c6174b],.nav-item span[data-v-a4c6174b],.user-name[data-v-a4c6174b],.logout-btn span[data-v-a4c6174b]{display:none}.brand[data-v-a4c6174b]{justify-content:center;padding:18px 10px}.nav-item[data-v-a4c6174b]{justify-content:center}.main[data-v-a4c6174b]{margin-left:64px}.main.no-sidebar[data-v-a4c6174b]{margin-left:0}}
|
|
||||||
1
web/dist/assets/MainLayout-Cavyx6zq.js
vendored
Normal file
1
web/dist/assets/MainLayout-Cavyx6zq.js
vendored
Normal file
@@ -0,0 +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};
|
||||||
1
web/dist/assets/MainLayout-CsFkTHMI.js
vendored
1
web/dist/assets/MainLayout-CsFkTHMI.js
vendored
@@ -1 +0,0 @@
|
|||||||
import{k as h,o as c,c as m,a as s,b as e,w as t,m as d,n as _,t as v,p as C,r as x,q as w,d as i,u as L,e as n,v as M,x as A,y as B,z as E,A as D,B as N,f as V,C as z,D as I,E as S,F as q,G as F}from"./index-C_uWT3cF.js";import{_ as G}from"./_plugin-vue_export-helper-DlAUqK2U.js";const R={class:"layout"},T={key:0,class:"sidebar"},$={class:"nav"},j={class:"sidebar-footer"},H={class:"user-info"},J={class:"user-name"},K={class:"main-inner"},O={__name:"MainLayout",setup(P){const f=L(),u=w(()=>q().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 I()}catch{}F(),S.success("已退出"),f.push("/login")}return(k,a)=>{const l=i("el-icon"),r=i("router-link"),y=i("el-button"),b=i("router-view");return c(),m("div",R,[u.value?(c(),m("aside",T,[a[4]||(a[4]=s("div",{class:"brand"},[s("div",{class:"brand-logo"},"LM"),s("div",{class:"brand-text"},"LAN Manager")],-1)),s("nav",$,[e(r,{to:"/machines",class:"nav-item","active-class":"active"},{default:t(()=>[e(l,null,{default:t(()=>[e(n(M))]),_:1}),a[0]||(a[0]=s("span",null,"机器列表",-1))]),_:1}),u.value?(c(),d(r,{key:0,to:"/topology",class:"nav-item","active-class":"active"},{default:t(()=>[e(l,null,{default:t(()=>[e(n(A))]),_:1}),a[1]||(a[1]=s("span",null,"拓扑图",-1))]),_:1})):_("",!0),u.value?(c(),d(r,{key:1,to:"/logs",class:"nav-item","active-class":"active"},{default:t(()=>[e(l,null,{default:t(()=>[e(n(B))]),_:1}),a[2]||(a[2]=s("span",null,"操作日志",-1))]),_:1})):_("",!0)]),s("div",{class:"theme-toggle",onClick:p},[e(l,{class:"theme-icon"},{default:t(()=>[(c(),d(E(o.value?n(D):n(N))))]),_:1}),s("span",null,v(o.value?"浅色模式":"深色模式"),1)]),s("div",j,[s("div",H,[e(l,{class:"user-icon"},{default:t(()=>[e(n(V))]),_:1}),s("span",J,v(u.value?"管理员":"访客"),1)]),e(y,{text:"",class:"logout-btn",onClick:g},{default:t(()=>[e(l,null,{default:t(()=>[e(n(z))]),_:1}),a[3]||(a[3]=s("span",null,"退出",-1))]),_:1})])])):_("",!0),s("main",{class:C(["main",{"no-sidebar":!u.value}])},[s("div",K,[e(b)])],2)])}}},W=G(O,[["__scopeId","data-v-a4c6174b"]]);export{W as default};
|
|
||||||
1
web/dist/assets/MainLayout-DQN4KPkJ.css
vendored
Normal file
1
web/dist/assets/MainLayout-DQN4KPkJ.css
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.layout[data-v-dac2493b]{display:flex;min-height:100vh}.sidebar[data-v-dac2493b]{width:220px;background:#0f172a;color:#fff;display:flex;flex-direction:column;position:fixed;left:0;top:0;bottom:0;z-index:100}.brand[data-v-dac2493b]{padding:22px 18px 14px;display:flex;align-items:center;gap:10px;border-bottom:1px solid rgba(255,255,255,.06)}.brand-logo[data-v-dac2493b]{width:32px;height:32px;border-radius:8px;background:linear-gradient(135deg,#3b82f6,#60a5fa);display:flex;align-items:center;justify-content:center;font-weight:800;font-size:13px}.brand-text[data-v-dac2493b]{font-weight:700;font-size:14px;letter-spacing:.3px}.nav[data-v-dac2493b]{flex:1;padding:12px 10px;display:flex;flex-direction:column;gap:4px}.nav-item[data-v-dac2493b]{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;color:#ffffffa6;text-decoration:none;font-size:13px;transition:background .15s ease,color .15s ease}.nav-item[data-v-dac2493b]:hover{background:#ffffff0f;color:#ffffffe6}.nav-item.active[data-v-dac2493b]{background:#3b82f62e;color:#60a5fa;font-weight:600}.nav-item .el-icon[data-v-dac2493b]{font-size:16px}.sidebar-footer[data-v-dac2493b]{padding:12px 10px 16px;border-top:1px solid rgba(255,255,255,.06);display:flex;flex-direction:column;gap:6px}.user-info[data-v-dac2493b]{display:flex;align-items:center;gap:8px;padding:8px 10px;font-size:12px;color:#ffffff8c}.user-icon[data-v-dac2493b]{font-size:14px}.user-name[data-v-dac2493b]{font-weight:500;color:#ffffffd9}.logout-btn[data-v-dac2493b]{justify-content:flex-start;width:100%;color:#ffffff8c;padding:8px 10px;border-radius:8px}.logout-btn[data-v-dac2493b]:hover{color:#fff;background:#ffffff0f}.logout-btn span[data-v-dac2493b]{margin-left:8px;font-size:12px}.main[data-v-dac2493b]{flex:1;margin-left:220px;min-height:100vh;background:var(--bg)}.main-inner[data-v-dac2493b]{padding:10px}.theme-toggle[data-v-dac2493b]{margin:0 10px 10px;display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:8px;color:#ffffff8c;font-size:13px;cursor:pointer;transition:background .15s ease,color .15s ease}.theme-toggle[data-v-dac2493b]:hover{background:#ffffff0f;color:#ffffffe6}.theme-icon[data-v-dac2493b]{font-size:16px}.main.no-sidebar[data-v-dac2493b]{margin-left:0}@media (max-width: 768px){.sidebar[data-v-dac2493b]{width:64px}.brand-text[data-v-dac2493b],.nav-item span[data-v-dac2493b],.user-name[data-v-dac2493b],.logout-btn span[data-v-dac2493b]{display:none}.brand[data-v-dac2493b]{justify-content:center;padding:18px 10px}.nav-item[data-v-dac2493b]{justify-content:center}.main[data-v-dac2493b]{margin-left:64px}.main.no-sidebar[data-v-dac2493b]{margin-left:0}}
|
||||||
1
web/dist/assets/PVEHosts-BMDl3QRA.css
vendored
Normal file
1
web/dist/assets/PVEHosts-BMDl3QRA.css
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.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-Ch6D9CK9.js
vendored
Normal file
1
web/dist/assets/PVEHosts-Ch6D9CK9.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
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};
|
||||||
467
web/dist/assets/Topology-BJXdT35q.js
vendored
467
web/dist/assets/Topology-BJXdT35q.js
vendored
File diff suppressed because one or more lines are too long
467
web/dist/assets/Topology-BoCWnE97.js
vendored
Normal file
467
web/dist/assets/Topology-BoCWnE97.js
vendored
Normal file
File diff suppressed because one or more lines are too long
467
web/dist/assets/Topology-CVKO0hET.js
vendored
467
web/dist/assets/Topology-CVKO0hET.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
96
web/dist/assets/index-Chagxl0Z.js
vendored
96
web/dist/assets/index-Chagxl0Z.js
vendored
File diff suppressed because one or more lines are too long
2
web/dist/index.html
vendored
2
web/dist/index.html
vendored
@@ -5,7 +5,7 @@
|
|||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>局域网机器管理后台</title>
|
<title>局域网机器管理后台</title>
|
||||||
<script type="module" crossorigin src="/assets/index-C_uWT3cF.js"></script>
|
<script type="module" crossorigin src="/assets/index-BFjouPFU.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-DHYRt9JF.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-DHYRt9JF.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
Reference in New Issue
Block a user