fix: 修改内存的基础单位为kb
Build and Deploy Vue3 / build (push) Successful in 2m38s
Build and Deploy Vue3 / deploy (push) Successful in 1m3s

This commit is contained in:
2026-03-21 15:25:38 +08:00
parent cf19956b88
commit 9edb59d16e
14 changed files with 819 additions and 155 deletions
+50 -9
View File
@@ -72,27 +72,36 @@
<div class="config-row">
<div class="config-cell">
<span class="config-label">认证Token</span>
<span class="config-value">
<span class="config-value secret-cell">
<template v-if="detail.token">
<code>{{ showToken ? detail.token : '••••••••••••' }}</code>
<el-button link type="primary" size="small" @click="showToken = !showToken">{{ showToken ? '隐藏' : '显示' }}</el-button>
<el-button v-if="showToken" link type="primary" size="small" @click="copyText(detail.token)">复制</el-button>
</template>
<span v-else class="text-muted">未设置</span>
</span>
</div>
<div class="config-cell">
<span class="config-label">SSH 密码</span>
<span class="config-value">
<span class="config-value secret-cell">
<template v-if="detail.password">
<code>{{ showPassword ? detail.password : '••••••••' }}</code>
<el-button link type="primary" size="small" @click="showPassword = !showPassword">{{ showPassword ? '隐藏' : '显示' }}</el-button>
<el-button v-if="showPassword" link type="primary" size="small" @click="copyText(detail.password)">复制</el-button>
</template>
<span v-else class="text-muted">未设置</span>
</span>
</div>
<div class="config-cell">
<span class="config-label">私钥路径</span>
<span class="config-value mono-text">{{ detail.private_key_path || '-' }}</span>
<span class="config-label">私钥</span>
<span class="config-value secret-cell">
<template v-if="detail.private_key">
<code>{{ showPrivateKey ? detail.private_key.substring(0, 40) + '...' : '••••••••••••' }}</code>
<el-button link type="primary" size="small" @click="showPrivateKey = !showPrivateKey">{{ showPrivateKey ? '隐藏' : '显示' }}</el-button>
<el-button v-if="showPrivateKey" link type="primary" size="small" @click="copyText(detail.private_key)">复制</el-button>
</template>
<span v-else class="text-muted">未设置</span>
</span>
</div>
</div>
<div class="config-row">
@@ -176,6 +185,12 @@
<el-tab-pane label="虚拟机管理" name="vm">
<VmManage v-if="hostTabLoaded['vm']" />
</el-tab-pane>
<el-tab-pane label="快照管理" name="snapshot">
<SnapshotManage v-if="hostTabLoaded['snapshot']" />
</el-tab-pane>
<el-tab-pane label="备份管理" name="backup">
<BackupManage v-if="hostTabLoaded['backup']" />
</el-tab-pane>
</el-tabs>
</div>
@@ -190,7 +205,7 @@
<el-form-item label="SSH 端口"><el-input-number v-model="formData.port" :min="0" :max="65535" style="width: 100%" /></el-form-item>
<el-form-item label="SSH 用户名"><el-input v-model="formData.user" /></el-form-item>
<el-form-item label="SSH 密码"><el-input v-model="formData.password" show-password /></el-form-item>
<el-form-item label="私钥路径"><el-input v-model="formData.private_key_path" /></el-form-item>
<el-form-item label="私钥"><el-input v-model="formData.private_key" type="textarea" :rows="4" placeholder="SSH 私钥内容" /></el-form-item>
<el-divider content-position="left">资源限制</el-divider>
<el-form-item label="最大CPU(核)"><el-input-number v-model="formData.max_cpu" :min="0" controls-position="right" style="width: 100%" /></el-form-item>
<el-row :gutter="16">
@@ -252,6 +267,8 @@ import ImageManage from '@/views/virtualization/ImageManage.vue'
import NetworkManage from '@/views/virtualization/NetworkManage.vue'
import VolumeManage from '@/views/virtualization/VolumeManage.vue'
import VmManage from '@/views/virtualization/VmManage.vue'
import SnapshotManage from '@/views/virtualization/SnapshotManage.vue'
import BackupManage from '@/views/virtualization/BackupManage.vue'
import { useTagsViewStore } from '@/store/tagsViewStore'
import * as echarts from 'echarts'
@@ -264,7 +281,7 @@ const serviceName = computed(() => route.query.service_name || '')
const hostId = computed(() => parseInt(route.query.id) || 0)
const activeTab = ref('info')
const hostTabLoaded = reactive({ image: false, network: false, volume: false, vm: false })
const hostTabLoaded = reactive({ image: false, network: false, volume: false, vm: false, snapshot: false, backup: false })
watch(activeTab, (tab) => {
if (!['info', 'monitor'].includes(tab) && !hostTabLoaded[tab]) hostTabLoaded[tab] = true
@@ -283,13 +300,34 @@ const metricsLoading = ref(false)
const detail = ref(null)
const showToken = ref(false)
const showPassword = ref(false)
const showPrivateKey = ref(false)
const copyText = (text) => {
if (!text) return
if (navigator.clipboard?.writeText) {
navigator.clipboard.writeText(text).then(() => ElMessage.success('已复制到剪贴板')).catch(() => fallbackCopy(text))
} else {
fallbackCopy(text)
}
}
const fallbackCopy = (text) => {
const ta = document.createElement('textarea')
ta.value = text
ta.style.cssText = 'position:fixed;left:-9999px;top:-9999px'
document.body.appendChild(ta)
ta.select()
try {
document.execCommand('copy')
ElMessage.success('已复制到剪贴板')
} catch { ElMessage.error('复制失败') }
document.body.removeChild(ta)
}
const metricsData = ref(null)
const editDialogVisible = ref(false)
const showGroupSelector = ref(false)
const formRef = ref(null)
const formData = reactive({
name: '', base_url: '', ip: '', token: '', port: 22, user: '', password: '', private_key_path: '',
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: ''
})
const formRules = {
@@ -501,7 +539,7 @@ const handleEdit = () => {
const d = detail.value
Object.assign(formData, {
name: d.name || '', base_url: d.base_url || '', ip: d.ip || '', token: d.token || '',
port: d.port || 22, user: d.user || '', password: d.password || '', private_key_path: d.private_key_path || '',
port: d.port || 22, user: d.user || '', password: d.password || '', private_key: d.private_key || '',
max_cpu: d.max_cpu || 0, max_memory: d.max_memory || 0, max_disk: d.max_disk || 0,
rx_bandwidth: d.rx_bandwidth || 0, tx_bandwidth: d.tx_bandwidth || 0,
host_group_id: d.host_group_id || 0, description: d.description || ''
@@ -517,7 +555,7 @@ const handleSubmit = () => {
const payload = { ...formData, service_id: serviceId.value, id: hostId.value }
if (!payload.token) delete payload.token
if (!payload.password) delete payload.password
if (!payload.private_key_path) delete payload.private_key_path
if (!payload.private_key) delete payload.private_key
if (!payload.description) delete payload.description
if (!payload.host_group_id) delete payload.host_group_id
const res = await updateRemoteHost(payload)
@@ -554,6 +592,7 @@ const initPage = () => {
detail.value = null
showToken.value = false
showPassword.value = false
showPrivateKey.value = false
metricsData.value = null
metricsHistory.times.length = 0
metricsHistory.cpu.length = 0
@@ -616,6 +655,8 @@ onBeforeUnmount(() => { isPageActive = false; stopPolling(); disposeCharts() })
.config-cell:last-child { border-right: none; }
.config-label { display: block; font-size: 12px; color: #86909c; margin-bottom: 4px; }
.config-value { display: block; font-size: 14px; color: #1d2129; word-break: break-all; }
.secret-cell { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.secret-cell code { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mono-text { font-family: 'Consolas', 'Monaco', monospace; }
.text-muted { color: #c0c4cc; }