From f10fc599f806eb2735d672ede8bf4da137e8058b Mon Sep 17 00:00:00 2001 From: shirainbown Date: Fri, 19 Jun 2026 14:12:47 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E5=86=97?= =?UTF-8?q?=E4=BD=99checkAuth=E8=B0=83=E7=94=A8=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=AE=BF=E5=AE=A2=E5=8D=A1=E7=89=87=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/views/Dashboard.vue | 3 +- web/src/views/MachineDetail.vue | 3 +- web/src/views/MachineList.vue | 309 ++++++++++++++++++++------------ 3 files changed, 198 insertions(+), 117 deletions(-) diff --git a/web/src/views/Dashboard.vue b/web/src/views/Dashboard.vue index ac7749e..525bd28 100644 --- a/web/src/views/Dashboard.vue +++ b/web/src/views/Dashboard.vue @@ -184,7 +184,7 @@ import { PieChart, Lightning, Cpu, VideoPlay, Link, Timer, List, ArrowRight, Refresh, Grid, Platform, Service } from '@element-plus/icons-vue' -import { fetchMachines, fetchAllServices, fetchRelationships, fetchPVEHosts, checkAuth } from '@/api' +import { fetchMachines, fetchAllServices, fetchRelationships, fetchPVEHosts } from '@/api' import { getAuth } from '@/router' const isAdmin = getAuth().is_admin @@ -240,7 +240,6 @@ const pveMachines = computed(() => { onMounted(async () => { await load() - await checkAuth() }) async function load() { diff --git a/web/src/views/MachineDetail.vue b/web/src/views/MachineDetail.vue index db7c0d4..5d4d929 100644 --- a/web/src/views/MachineDetail.vue +++ b/web/src/views/MachineDetail.vue @@ -369,7 +369,7 @@ import { fetchServices, createService, updateService, deleteService, fetchRelationships, createRelationship, updateRelationship, deleteRelationship, sshInfo, syncSSH, fetchMachines, fetchOfflineLogs, fetchPVEHosts, - checkAuth, uiRefreshInterval, + uiRefreshInterval, startVM as apiStartVM, stopVM as apiStopVM, fetchVMStatus, } from '@/api' import { getAuth } from '@/router' @@ -424,7 +424,6 @@ onMounted(async () => { } catch (e) {} await loadVMStatus() } - await checkAuth() const interval = uiRefreshInterval || 10000 if (interval > 0) { timer = setInterval(async () => { diff --git a/web/src/views/MachineList.vue b/web/src/views/MachineList.vue index 3561142..919061d 100644 --- a/web/src/views/MachineList.vue +++ b/web/src/views/MachineList.vue @@ -30,112 +30,153 @@
-
-
-
- - - - {{ osShort(m.os_type) }} -
- {{ m.hostname }} - - - {{ m.is_online ? '在线' : '离线' }} - - - {{ m.service_count }} - -
-
- - {{ m.ip }} - - - {{ m.os_type }} - - {{ m.os_version }} - - {{ m.uptime }} - - - - - {{ m.pve_vm_status === 'running' ? 'VM运行中' : m.pve_vm_status === 'stopped' ? 'VM已停止' : 'VM检测中' }} +
+
+
+
+ + + + {{ osShort(m.os_type) }} +
+ {{ m.hostname }} + + + {{ m.is_online ? '在线' : '离线' }} - + + {{ m.service_count }} + +
+
+ + {{ m.ip }} + + + {{ m.os_type }} + + {{ m.os_version }} + + {{ m.uptime }} + + + + + {{ m.pve_vm_status === 'running' ? 'VM运行中' : m.pve_vm_status === 'stopped' ? 'VM已停止' : 'VM检测中' }} + + +
-
-
-
-
- +
+
+
+ +
+
+
CPU
+
+
+
{{ extractPercent(m.cpu_info) }}%
-
-
CPU
-
+
+
+ +
+
+
RAM
+
+
+
{{ extractDetail(m.memory_info) }}
+
+
+
+ +
+
+
DISK
+
+
+
{{ getMainDisk(m.disk_info).detail }}
-
{{ extractPercent(m.cpu_info) }}%
-
-
- -
-
-
RAM
-
-
-
{{ extractDetail(m.memory_info) }}
-
-
-
- -
-
-
DISK
-
-
-
{{ getMainDisk(m.disk_info).detail }}
-
-
-
- - {{ p.trim() }} - - +{{ m.listen_ports.split(',').length - 6 }} -
+
+ + {{ p.trim() }} + + +{{ m.listen_ports.split(',').length - 6 }} +
-
- - 同步于 {{ formatTime(m.ssh_synced_at) }} +
+ + 同步于 {{ formatTime(m.ssh_synced_at) }} +
- -
-
-
-
- - - - {{ osShort(m.os_type) }} + +
+
+
+
+
+ + + + {{ osShort(m.os_type) }} +
+ {{ m.hostname }} + + + {{ m.is_online ? '在线' : '离线' }} + +
+
+ + {{ m.ip }} + + + {{ m.os_type }} {{ m.os_version || '' }} +
- {{ m.hostname }} - - - {{ m.is_online ? '在线' : '离线' }} -
-
- - {{ m.os_type }} - + + +
+
+
+ +
+
+
CPU
+
+
+
{{ extractPercent(m.cpu_info) }}%
+
+
+
+ +
+
+
RAM
+
+
+
{{ extractDetail(m.memory_info) }}
+
+
+
+ +
+
+
DISK
+
+
+
{{ getMainDisk(m.disk_info).detail }}
+
@@ -238,7 +279,7 @@ import { Collection, Histogram, Connection, Clock, VideoPlay, VideoPause, Lock, User, Key, EditPen, Grid, InfoFilled, Warning } from '@element-plus/icons-vue' -import { fetchMachines, createMachine, updateMachine, checkAuth, uiRefreshInterval, exportData, importData, fetchPVEHosts, fetchVMStatus } from '@/api' +import { fetchMachines, createMachine, updateMachine, uiRefreshInterval, exportData, importData, fetchPVEHosts, fetchVMStatus } from '@/api' import { getAuth } from '@/router' import { ElMessage } from 'element-plus' @@ -255,7 +296,6 @@ let timer = null onMounted(async () => { await load() - await checkAuth() if (isAdmin) { try { const res = await fetchPVEHosts() @@ -431,7 +471,7 @@ function formatTime(t) { display: flex; align-items: center; gap: 12px; - margin-bottom: 20px; + margin-bottom: 24px; flex-wrap: wrap; } .search-wrap { @@ -455,39 +495,82 @@ function formatTime(t) { .cards-grid { display: grid; grid-template-columns: repeat(2, 1fr); - gap: 16px; + gap: 20px; } @media (max-width: 900px) { .cards-grid { grid-template-columns: 1fr; } } +/* ─── Neon Tech Card ─── */ .server-card { + position: relative; background: var(--card-bg); border-radius: var(--radius); - padding: 18px; box-shadow: var(--shadow-card); border: 1px solid var(--border); - border-left: 3px solid var(--border); cursor: pointer; - transition: all .15s ease; + transition: all .3s ease; + overflow: hidden; } -.server-card:hover { - transform: translateY(-2px); - box-shadow: var(--shadow-lg); - border-color: var(--border-strong); + +/* OS 顶部色条 — 使用 border-top */ +.server-card.os-linux { + border-top: 3px solid #58a6ff; } -.server-card.guest-card { - cursor: default; +.server-card.os-windows { + border-top: 3px solid #3fb950; } -.server-card.guest-card:hover { - transform: none; - box-shadow: var(--shadow-card); - border-color: var(--border); +.server-card.os-macos { + border-top: 3px solid #a371f7; +} +.server-card.os-other { + border-top: 3px solid #8b949e; } .server-card.offline-card { - opacity: 0.7; - border-left-color: var(--danger); + border-top: 3px solid #f85149; + opacity: 0.85; } + +.server-card:hover.os-linux { + border-top: 4px solid #58a6ff; + box-shadow: 0 0 20px rgba(88, 166, 255, 0.15), 0 0 60px rgba(88, 166, 255, 0.08), var(--shadow-lg); +} +.server-card:hover.os-windows { + border-top: 4px solid #3fb950; + box-shadow: 0 0 20px rgba(63, 185, 80, 0.15), 0 0 60px rgba(63, 185, 80, 0.08), var(--shadow-lg); +} +.server-card:hover.os-macos { + border-top: 4px solid #a371f7; + box-shadow: 0 0 20px rgba(163, 113, 247, 0.15), 0 0 60px rgba(163, 113, 247, 0.08), var(--shadow-lg); +} +.server-card:hover.os-other { + border-top: 4px solid #8b949e; +} +.server-card.offline-card:hover { + border-top: 4px solid #f85149; + box-shadow: 0 0 20px rgba(248, 81, 73, 0.15), 0 0 60px rgba(248, 81, 73, 0.08), var(--shadow-lg); +} + +.server-card:hover { + transform: translateY(-3px); + border-color: var(--border-strong); +} + +.card-content { + position: relative; + z-index: 1; + background: var(--card-bg); + border-radius: 0 0 calc(var(--radius) - 1px) calc(var(--radius) - 1px); + padding: 16px 18px 18px; +} + +.server-card.public-card { + cursor: default; +} +.server-card.public-card:hover { + transform: translateY(-1px); +} + .server-card.offline-card .hostname { color: var(--text-muted); } @@ -495,7 +578,7 @@ function formatTime(t) { .card-header { display: flex; flex-direction: column; - gap: 6px; + gap: 8px; } .title-row { display: flex; @@ -578,7 +661,7 @@ function formatTime(t) { .vm-tag { font-size: 11px; height: 20px; padding: 0 8px; display: inline-flex; align-items: center; gap: 4px; } .stats-row { - margin-top: 14px; + margin-top: 16px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;