From 98678859cbf5d298d6491ad1bdab5a6722c9ee0a Mon Sep 17 00:00:00 2001 From: shiran Date: Thu, 14 May 2026 13:20:32 +0800 Subject: [PATCH] =?UTF-8?q?fix(admin/host):=20=E7=A1=AC=E7=9B=98IO?= =?UTF-8?q?=E9=99=90=E5=88=B6=E5=B8=A6=E5=AE=BD=E5=AD=97=E6=AE=B5=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E5=8A=A8=E6=80=81=E5=8D=95=E4=BD=8D=E9=80=89=E6=8B=A9?= =?UTF-8?q?(B/s~GB/s),=20=E5=B8=A6=E5=AE=BD=E4=B8=8EIOPS=E5=88=86=E7=BB=84?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E4=BF=AE=E5=A4=8D=E6=A0=87=E7=AD=BE=E6=BA=A2?= =?UTF-8?q?=E5=87=BA=20--=20=E7=BC=98=E7=94=B1:=20=E5=B8=A6=E5=AE=BD?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E7=9B=B4=E6=8E=A5=E5=B1=95=E7=A4=BAbytes?= =?UTF-8?q?=E5=8E=9F=E5=A7=8B=E5=80=BC=E4=B8=94=E6=A0=87=E7=AD=BE=E8=BF=87?= =?UTF-8?q?=E9=95=BF=E5=AF=BC=E8=87=B4=E6=8D=A2=E8=A1=8C=E9=94=99=E4=B9=B1?= =?UTF-8?q?=20--=20=E9=A2=84=E6=9C=9F:=20=E5=B8=A6=E5=AE=BD=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=8F=82=E7=85=A7=E5=86=85=E5=AD=98/=E7=A3=81?= =?UTF-8?q?=E7=9B=98=E6=96=B9=E5=BC=8F=E9=80=9A=E8=BF=87=E4=B8=8B=E6=8B=89?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=8D=95=E4=BD=8D(=E9=BB=98=E8=AE=A4MB/s),?= =?UTF-8?q?=20IOPS=E7=8B=AC=E7=AB=8B=E5=88=86=E7=BB=84,=20=E6=A0=87?= =?UTF-8?q?=E7=AD=BE=E7=AE=80=E5=8C=96=E4=B8=BA=E8=AF=BB=E5=8F=96/?= =?UTF-8?q?=E5=86=99=E5=85=A5/=E7=AA=81=E5=8F=91=E8=AF=BB=E5=8F=96/?= =?UTF-8?q?=E7=AA=81=E5=8F=91=E5=86=99=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- src/views/virtualization/HostDetail.vue | 101 +++++++++++++++----- src/views/virtualization/HostManage.vue | 92 ++++++++++++------ src/views/virtualization/HostTreeManage.vue | 85 ++++++++++++---- 3 files changed, 206 insertions(+), 72 deletions(-) diff --git a/src/views/virtualization/HostDetail.vue b/src/views/virtualization/HostDetail.vue index 959ad84..5916eae 100644 --- a/src/views/virtualization/HostDetail.vue +++ b/src/views/virtualization/HostDetail.vue @@ -137,10 +137,16 @@
-
-
- {{ f.label }} - {{ formatDiskIoVal(detail[f.key], f) }} +
+
+ {{ f.label }}带宽 + {{ formatDiskIoVal(detail[f.key], true) }} +
+
+
+
+ {{ f.label }} IOPS + {{ formatDiskIoVal(detail[f.key], false) }}
@@ -428,11 +434,24 @@ 可选,不展开则使用默认值
-
- - - {{ f.unit }} - +
+
+ 带宽限制 + + + +
+
+ + + +
+
IOPS 限制
+
+ + + +
@@ -508,11 +527,24 @@ 可选,不展开则使用默认值
-
- - - {{ f.unit }} - +
+
+ 带宽限制 + + + +
+
+ + + +
+
IOPS 限制
+
+ + + +
@@ -676,25 +708,42 @@ const diskIoDefaults = { read_bytes_sec_max: 314572800, write_bytes_sec_max: 314572800, read_iops_sec_max: 1000, write_iops_sec_max: 1000 } -const diskIoFields = [ - { key: 'read_bytes_sec', label: '读取带宽', unit: 'B/s', isBandwidth: true }, - { key: 'write_bytes_sec', label: '写入带宽', unit: 'B/s', isBandwidth: true }, - { key: 'read_iops_sec', label: '读取 IOPS', unit: 'IOPS', isBandwidth: false }, - { key: 'write_iops_sec', label: '写入 IOPS', unit: 'IOPS', isBandwidth: false }, - { key: 'read_bytes_sec_max', label: '突发读取带宽', unit: 'B/s', isBandwidth: true }, - { key: 'write_bytes_sec_max', label: '突发写入带宽', unit: 'B/s', isBandwidth: true }, - { key: 'read_iops_sec_max', label: '突发读取 IOPS', unit: 'IOPS', isBandwidth: false }, - { key: 'write_iops_sec_max', label: '突发写入 IOPS', unit: 'IOPS', isBandwidth: false } +const diskIoBwFields = [ + { key: 'read_bytes_sec', label: '读取' }, + { key: 'write_bytes_sec', label: '写入' }, + { key: 'read_bytes_sec_max', label: '突发读取' }, + { key: 'write_bytes_sec_max', label: '突发写入' } ] -const formatDiskIoVal = (val, field) => { +const diskIoIopsFields = [ + { key: 'read_iops_sec', label: '读取' }, + { key: 'write_iops_sec', label: '写入' }, + { key: 'read_iops_sec_max', label: '突发读取' }, + { key: 'write_iops_sec_max', label: '突发写入' } +] +const diskIoFields = [ + ...diskIoBwFields.map(f => ({ ...f, isBandwidth: true })), + ...diskIoIopsFields.map(f => ({ ...f, isBandwidth: false })) +] +const formatDiskIoVal = (val, isBandwidth) => { if (!val && val !== 0) return '-' val = Number(val) - if (!field.isBandwidth) return val.toLocaleString() + ' ' + field.unit + if (!isBandwidth) return val.toLocaleString() + ' IOPS' if (val >= 1073741824) return (val / 1073741824).toFixed(1) + ' GB/s' if (val >= 1048576) return (val / 1048576).toFixed(0) + ' MB/s' if (val >= 1024) return (val / 1024).toFixed(0) + ' KB/s' return val + ' B/s' } +const ioBwUnitOptions = [ + { label: 'B/s', factor: 1 }, + { label: 'KB/s', factor: 1024 }, + { label: 'MB/s', factor: 1048576 }, + { label: 'GB/s', factor: 1073741824 } +] +const ioBwUnit = ref('MB/s') +const tokenIoBwUnit = ref('MB/s') +const getIoBwFactor = () => ioBwUnitOptions.find(u => u.label === ioBwUnit.value)?.factor || 1048576 +const getTokenIoBwFactor = () => ioBwUnitOptions.find(u => u.label === tokenIoBwUnit.value)?.factor || 1048576 + const showDiskIoSection = ref(false) const showTokenDiskIo = ref(false) const showDetailDiskIo = ref(false) @@ -1058,6 +1107,7 @@ const openTokenDialog = () => { tokenMemUnit.value = 'GB' tokenDiskUnit.value = 'GB' showTokenDiskIo.value = false + tokenIoBwUnit.value = 'MB/s' tokenDialogVisible.value = true } @@ -1377,5 +1427,6 @@ onBeforeUnmount(() => { isPageActive = false; disposeCharts() }) .section-hint { font-size: 12px; color: #909399; font-weight: 400; } .tk-section-title.clickable { cursor: pointer; user-select: none; display: flex; align-items: center; gap: 6px; } .tk-section-title.clickable:hover { color: #409eff; } +.io-sub-title { font-size: 13px; font-weight: 500; color: #606266; margin: 12px 0 8px; display: flex; align-items: center; } diff --git a/src/views/virtualization/HostManage.vue b/src/views/virtualization/HostManage.vue index f2f4c37..b2f1feb 100644 --- a/src/views/virtualization/HostManage.vue +++ b/src/views/virtualization/HostManage.vue @@ -165,11 +165,24 @@ 可选,不展开则使用默认值
-
- - - {{ f.unit }} - +
+
+ 带宽限制 + + + +
+
+ + + +
+
IOPS 限制
+
+ + + +
@@ -290,11 +303,24 @@ 可选,不展开则使用默认值
-
- - - {{ f.unit }} - +
+
+ 带宽限制 + + + +
+
+ + + +
+
IOPS 限制
+
+ + + +
@@ -450,25 +476,32 @@ const diskIoDefaults = { read_bytes_sec_max: 314572800, write_bytes_sec_max: 314572800, read_iops_sec_max: 1000, write_iops_sec_max: 1000 } -const diskIoFields = [ - { key: 'read_bytes_sec', label: '读取带宽', unit: 'B/s', isBandwidth: true }, - { key: 'write_bytes_sec', label: '写入带宽', unit: 'B/s', isBandwidth: true }, - { key: 'read_iops_sec', label: '读取 IOPS', unit: 'IOPS', isBandwidth: false }, - { key: 'write_iops_sec', label: '写入 IOPS', unit: 'IOPS', isBandwidth: false }, - { key: 'read_bytes_sec_max', label: '突发读取带宽', unit: 'B/s', isBandwidth: true }, - { key: 'write_bytes_sec_max', label: '突发写入带宽', unit: 'B/s', isBandwidth: true }, - { key: 'read_iops_sec_max', label: '突发读取 IOPS', unit: 'IOPS', isBandwidth: false }, - { key: 'write_iops_sec_max', label: '突发写入 IOPS', unit: 'IOPS', isBandwidth: false } +const diskIoBwFields = [ + { key: 'read_bytes_sec', label: '读取' }, + { key: 'write_bytes_sec', label: '写入' }, + { key: 'read_bytes_sec_max', label: '突发读取' }, + { key: 'write_bytes_sec_max', label: '突发写入' } ] -const formatDiskIoVal = (val, field) => { - if (!val && val !== 0) return '-' - val = Number(val) - if (!field.isBandwidth) return val.toLocaleString() + ' ' + field.unit - if (val >= 1073741824) return (val / 1073741824).toFixed(1) + ' GB/s' - if (val >= 1048576) return (val / 1048576).toFixed(0) + ' MB/s' - if (val >= 1024) return (val / 1024).toFixed(0) + ' KB/s' - return val + ' B/s' -} +const diskIoIopsFields = [ + { key: 'read_iops_sec', label: '读取' }, + { key: 'write_iops_sec', label: '写入' }, + { key: 'read_iops_sec_max', label: '突发读取' }, + { key: 'write_iops_sec_max', label: '突发写入' } +] +const diskIoFields = [ + ...diskIoBwFields.map(f => ({ ...f, isBandwidth: true })), + ...diskIoIopsFields.map(f => ({ ...f, isBandwidth: false })) +] +const ioBwUnitOptions = [ + { label: 'B/s', factor: 1 }, + { label: 'KB/s', factor: 1024 }, + { label: 'MB/s', factor: 1048576 }, + { label: 'GB/s', factor: 1073741824 } +] +const ioBwUnit = ref('MB/s') +const tokenIoBwUnit = ref('MB/s') +const getIoBwFactor = () => ioBwUnitOptions.find(u => u.label === ioBwUnit.value)?.factor || 1048576 +const getTokenIoBwFactor = () => ioBwUnitOptions.find(u => u.label === tokenIoBwUnit.value)?.factor || 1048576 const showDiskIoSection = ref(false) const showTokenDiskIo = ref(false) @@ -581,6 +614,7 @@ const resetForm = () => { _groupName: '', ...diskIoDefaults }) showDiskIoSection.value = false + ioBwUnit.value = 'MB/s' } const handleHostGroupSelected = (group) => { @@ -816,6 +850,7 @@ const openTokenDialog = () => { tokenMemUnit.value = 'GB' tokenDiskUnit.value = 'GB' showTokenDiskIo.value = false + tokenIoBwUnit.value = 'MB/s' tokenDialogVisible.value = true } @@ -900,4 +935,5 @@ onMounted(() => { .section-arrow { transition: transform 0.2s; font-size: 14px; } .section-arrow.expanded { transform: rotate(90deg); } .section-hint { font-size: 12px; color: #909399; font-weight: 400; } +.io-sub-title { font-size: 13px; font-weight: 500; color: #606266; margin: 12px 0 8px; display: flex; align-items: center; } diff --git a/src/views/virtualization/HostTreeManage.vue b/src/views/virtualization/HostTreeManage.vue index 4b1584a..39dc89c 100644 --- a/src/views/virtualization/HostTreeManage.vue +++ b/src/views/virtualization/HostTreeManage.vue @@ -137,11 +137,24 @@ 可选,不展开则使用默认值
-
- - - {{ f.unit }} - +
+
+ 带宽限制 + + + +
+
+ + + +
+
IOPS 限制
+
+ + + +
@@ -345,11 +358,24 @@ 可选,不展开则使用默认值
-
- - - {{ f.unit }} - +
+
+ 带宽限制 + + + +
+
+ + + +
+
IOPS 限制
+
+ + + +
@@ -657,16 +683,33 @@ const diskIoDefaults = { read_bytes_sec_max: 314572800, write_bytes_sec_max: 314572800, read_iops_sec_max: 1000, write_iops_sec_max: 1000 } -const diskIoFields = [ - { key: 'read_bytes_sec', label: '读取带宽', unit: 'B/s', isBandwidth: true }, - { key: 'write_bytes_sec', label: '写入带宽', unit: 'B/s', isBandwidth: true }, - { key: 'read_iops_sec', label: '读取 IOPS', unit: 'IOPS', isBandwidth: false }, - { key: 'write_iops_sec', label: '写入 IOPS', unit: 'IOPS', isBandwidth: false }, - { key: 'read_bytes_sec_max', label: '突发读取带宽', unit: 'B/s', isBandwidth: true }, - { key: 'write_bytes_sec_max', label: '突发写入带宽', unit: 'B/s', isBandwidth: true }, - { key: 'read_iops_sec_max', label: '突发读取 IOPS', unit: 'IOPS', isBandwidth: false }, - { key: 'write_iops_sec_max', label: '突发写入 IOPS', unit: 'IOPS', isBandwidth: false } +const diskIoBwFields = [ + { key: 'read_bytes_sec', label: '读取' }, + { key: 'write_bytes_sec', label: '写入' }, + { key: 'read_bytes_sec_max', label: '突发读取' }, + { key: 'write_bytes_sec_max', label: '突发写入' } ] +const diskIoIopsFields = [ + { key: 'read_iops_sec', label: '读取' }, + { key: 'write_iops_sec', label: '写入' }, + { key: 'read_iops_sec_max', label: '突发读取' }, + { key: 'write_iops_sec_max', label: '突发写入' } +] +const diskIoFields = [ + ...diskIoBwFields.map(f => ({ ...f, isBandwidth: true })), + ...diskIoIopsFields.map(f => ({ ...f, isBandwidth: false })) +] +const ioBwUnitOptions = [ + { label: 'B/s', factor: 1 }, + { label: 'KB/s', factor: 1024 }, + { label: 'MB/s', factor: 1048576 }, + { label: 'GB/s', factor: 1073741824 } +] +const hostIoBwUnit = ref('MB/s') +const tokenIoBwUnit = ref('MB/s') +const getHostIoBwFactor = () => ioBwUnitOptions.find(u => u.label === hostIoBwUnit.value)?.factor || 1048576 +const getTokenIoBwFactor = () => ioBwUnitOptions.find(u => u.label === tokenIoBwUnit.value)?.factor || 1048576 + const showHostDiskIo = ref(false) const showTokenDiskIo = ref(false) @@ -690,6 +733,7 @@ const handleAddHost = () => { hostDialogType.value = 'add' Object.assign(hostForm, { id: undefined, name: '', base_url: '', ip: '', token: '', port: 22, user: '', password: '', private_key: '', max_cpu: 0, max_memory: 0, max_disk: 0, rx_bandwidth: 0, tx_bandwidth: 0, host_group_id: 0, description: '', ...diskIoDefaults }) showHostDiskIo.value = false + hostIoBwUnit.value = 'MB/s' hostDialogVisible.value = true } @@ -697,6 +741,7 @@ const handleAddHostToGroup = (group) => { hostDialogType.value = 'add' Object.assign(hostForm, { id: undefined, name: '', base_url: '', ip: '', token: '', port: 22, user: '', password: '', private_key: '', max_cpu: 0, max_memory: 0, max_disk: 0, rx_bandwidth: 0, tx_bandwidth: 0, host_group_id: group.id, description: '', ...diskIoDefaults }) showHostDiskIo.value = false + hostIoBwUnit.value = 'MB/s' hostDialogVisible.value = true } @@ -809,6 +854,7 @@ const openTokenDialog = () => { tokenMemUnit.value = 'GB' tokenDiskUnit.value = 'GB' showTokenDiskIo.value = false + tokenIoBwUnit.value = 'MB/s' tokenDialogVisible.value = true } @@ -899,4 +945,5 @@ onMounted(() => { if (serviceId.value) loadTreeData() }) .section-arrow { transition: transform 0.2s; font-size: 14px; } .section-arrow.expanded { transform: rotate(90deg); } .section-hint { font-size: 12px; color: #909399; font-weight: 400; } +.io-sub-title { font-size: 13px; font-weight: 500; color: #606266; margin: 12px 0 8px; display: flex; align-items: center; }