From fcaad4b3ae210ec59b8019501c0979a2a91f7302 Mon Sep 17 00:00:00 2001
From: zxr <271055687@qq.com>
Date: Mon, 29 Jun 2026 10:09:28 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E7=A9=BA=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=E6=97=B6=E9=A1=B5=E9=9D=A2=E7=BB=84=E4=BB=B6=E4=B8=8D?=
=?UTF-8?q?=E6=98=BE=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.env.development | 3 +-
config/vite.config.dev.ts | 30 +++++
src/api/ops/server.ts | 7 ++
src/views/ops/pages/dc/server/index.vue | 146 ++++++++++++++----------
4 files changed, 122 insertions(+), 64 deletions(-)
diff --git a/.env.development b/.env.development
index 3cbdb98..f864fbc 100644
--- a/.env.development
+++ b/.env.development
@@ -10,7 +10,8 @@ VITE_USE_MOCK=false
# API 基础URL
# VITE_API_BASE_URL=https://ops-api.apinb.com
-VITE_API_BASE_URL=http://127.0.0.1
+# 开发环境走 Vite 同源代理,避免依赖本机 80/443 nginx
+VITE_API_BASE_URL=
# Logs 本地调试地址(仅 logs 模块使用)
VITE_LOGS_API_BASE_URL=http://127.0.0.1:12440
diff --git a/config/vite.config.dev.ts b/config/vite.config.dev.ts
index 0ad4630..80e8c58 100644
--- a/config/vite.config.dev.ts
+++ b/config/vite.config.dev.ts
@@ -2,6 +2,11 @@ import { mergeConfig } from 'vite'
// import eslint from 'vite-plugin-eslint'
import baseConfig from './vite.config.base'
+const proxyTarget = (port: number) => ({
+ target: `http://127.0.0.1:${port}`,
+ changeOrigin: true,
+})
+
export default mergeConfig(
{
mode: 'development',
@@ -11,6 +16,31 @@ export default mergeConfig(
fs: {
strict: true,
},
+ proxy: {
+ '/rbac2': proxyTarget(10001),
+ '/Alert': proxyTarget(12427),
+ '/alert': proxyTarget(12427),
+ '/DC-Control': proxyTarget(3031),
+ '/dc-control': proxyTarget(3031),
+ '/dc-network': proxyTarget(12429),
+ '/DC-Hardware': proxyTarget(12450),
+ '/dc-hardware': proxyTarget(12450),
+ '/dc-host': proxyTarget(9030),
+ '/dc-middleware': proxyTarget(12428),
+ '/dc-database': proxyTarget(12580),
+ '/Feedback': proxyTarget(12432),
+ '/feedback': proxyTarget(12432),
+ '/Assets': proxyTarget(12430),
+ '/assets': proxyTarget(12430),
+ '/Logs': proxyTarget(12440),
+ '/logs': proxyTarget(12440),
+ '/Kb': proxyTarget(12434),
+ '/kb': proxyTarget(12434),
+ '/Mgt': proxyTarget(12436),
+ '/mgt': proxyTarget(12436),
+ '/Visual': proxyTarget(12438),
+ '/visual': proxyTarget(12438),
+ },
},
plugins: [
// eslint({
diff --git a/src/api/ops/server.ts b/src/api/ops/server.ts
index ed479f3..a910c61 100644
--- a/src/api/ops/server.ts
+++ b/src/api/ops/server.ts
@@ -162,6 +162,13 @@ export const fetchServerMetricsSummary = (serverIdentity: string) => {
})
}
+/** 立即拉取一次主机指标并返回最新统计卡片 */
+export const collectServerMetricsNow = (serverIdentity: string) => {
+ return request.post<{ code: number; details?: HostMetricsSummary; message?: string }>('/DC-Control/v1/servers/metrics/collect', {
+ server_identity: serverIdentity,
+ })
+}
+
/** 近 N 小时网络收/发速率(Mbps,相邻采样字节差分) */
export const fetchServerNetworkTraffic = (serverIdentity: string, hours = 6) => {
return request.get<{ code: number; details?: HostNetworkTrafficPayload; message?: string }>(
diff --git a/src/views/ops/pages/dc/server/index.vue b/src/views/ops/pages/dc/server/index.vue
index 54dcb0f..dede3b9 100644
--- a/src/views/ops/pages/dc/server/index.vue
+++ b/src/views/ops/pages/dc/server/index.vue
@@ -120,6 +120,12 @@
+
+
+
+
+ {{ isCollecting(record) ? '采集中' : '立即采集' }}
+
@@ -200,13 +206,7 @@ import ServerFormDialog from './components/ServerFormDialog.vue'
import QuickConfigDialog from './components/QuickConfigDialog.vue'
import HardwareDeviceConfigDialog from './components/HardwareDeviceConfigDialog.vue'
import { columns as columnsConfig } from './config/columns'
-import { fetchServerList, deleteServer } from '@/api/ops/server'
-import axios from 'axios'
-
-// 创建独立的 axios 实例用于请求外部 agent,绕过全局拦截器
-const agentAxios = axios.create({
- timeout: 5000,
-})
+import { fetchServerList, deleteServer, fetchServerMetricsSummary, collectServerMetricsNow, type HostMetricsSummary } from '@/api/ops/server'
const router = useRouter()
@@ -217,6 +217,7 @@ const formDialogVisible = ref(false)
const quickConfigVisible = ref(false)
const hardwareConfigVisible = ref(false)
const currentRecord = ref(null)
+const collectingMap = reactive>({})
const formModel = ref({
keyword: '',
collect_on: undefined as boolean | undefined,
@@ -394,6 +395,13 @@ const handleHardwareConfigSuccess = () => {
fetchServers()
}
+const getCollectingKey = (record: any) => record.server_identity || String(record.id || '')
+
+const isCollecting = (record: any) => {
+ const key = getCollectingKey(record)
+ return !!collectingMap[key]
+}
+
// 编辑服务器
const handleEdit = (record: any) => {
currentRecord.value = record
@@ -465,74 +473,86 @@ const handleDelete = async (record: any) => {
})
}
-/** dc-host `GET agent_config`(一般为 `/dc-host/stats`)返回裸 Metrics JSON */
-// 获取所有服务器的监控指标
+const resetMetrics = (record: any) => {
+ record.cpu_info = { value: 0, total: '', used: '' }
+ record.memory_info = { value: 0, total: '', used: '' }
+ record.disk_info = { value: 0, total: '', used: '' }
+}
+
+const applyMetricsSummary = (record: any, summary?: HostMetricsSummary) => {
+ if (!summary || !summary.has_data) {
+ resetMetrics(record)
+ return
+ }
+ record.cpu_info = {
+ value: Number((summary.cpu?.usage_percent || 0).toFixed(2)),
+ total: summary.cpu?.logical_cores_total ? `${summary.cpu.logical_cores_total}核` : '',
+ used: '',
+ }
+ record.memory_info = {
+ value: Number((summary.memory?.used_percent || 0).toFixed(2)),
+ total: summary.memory?.total_bytes ? `${(summary.memory.total_bytes / 1024 / 1024 / 1024).toFixed(1)}GB` : '',
+ used: summary.memory?.used_bytes ? `${(summary.memory.used_bytes / 1024 / 1024 / 1024).toFixed(1)}GB` : '',
+ }
+ record.disk_info = {
+ value: Number((summary.disk_root?.used_percent || 0).toFixed(2)),
+ total: summary.disk_root?.total_bytes ? `${(summary.disk_root.total_bytes / 1024 / 1024 / 1024).toFixed(0)}GB` : '',
+ used: summary.disk_root?.used_bytes ? `${(summary.disk_root.used_bytes / 1024 / 1024 / 1024).toFixed(0)}GB` : '',
+ }
+ if (summary.timestamp) {
+ record.last_check_time = summary.timestamp
+ }
+}
+
+// 从 dc-control 获取所有服务器最新时序指标
const getAllMetrics = async () => {
try {
- // 遍历每个服务器记录
const metricsPromises = tableData.value.map(async (record) => {
- // 检查是否有 agent_config 配置
- if (record.agent_config) {
- try {
- // 从 agent_config 中解析 URL
- let metricsUrl = record.agent_config
-
- // 验证 URL 是否合法
- try {
- new URL(metricsUrl)
- } catch (urlError) {
- console.warn(`服务器 ${record.name} 的 agent_config 不是合法的 URL:`, metricsUrl)
- // 设置默认值 0
- record.cpu_info = { value: 0, total: '', used: '' }
- record.memory_info = { value: 0, total: '', used: '' }
- record.disk_info = { value: 0, total: '', used: '' }
- return
- }
- // 使用独立的 axios 实例请求外部 agent,绕过全局拦截器
- const response = await agentAxios.get(metricsUrl)
- console.log('获取指标数据:', response.data)
- if (response.data) {
- // 更新记录的监控数据
- record.cpu_info = {
- value: Number((response.data.cpu_usage || 0).toFixed(2)),
- total: response.data.cpu?.length ? `${response.data.cpu.length}核` : '',
- used: '',
- }
-
- record.memory_info = {
- value: Number((response.data.mem_usage?.used_percent || 0).toFixed(2)),
- total: response.data.mem_usage?.total ? `${(response.data.mem_usage.total / 1024 / 1024 / 1024).toFixed(1)}GB` : '',
- used: response.data.mem_usage?.used ? `${(response.data.mem_usage.used / 1024 / 1024 / 1024).toFixed(1)}GB` : '',
- }
-
- record.disk_info = {
- value: Number((response.data.disk_usage?.used_percent || 0).toFixed(2)),
- total: response.data.disk_usage?.total ? `${(response.data.disk_usage.total / 1024 / 1024 / 1024).toFixed(0)}GB` : '',
- used: response.data.disk_usage?.used ? `${(response.data.disk_usage.used / 1024 / 1024 / 1024).toFixed(0)}GB` : '',
- }
- }
- } catch (error) {
- console.warn(`获取服务器 ${record.name} 的监控指标失败:`, error)
- // 初始化默认值
- record.cpu_info = { value: 0, total: '', used: '' }
- record.memory_info = { value: 0, total: '', used: '' }
- record.disk_info = { value: 0, total: '', used: '' }
- }
- } else {
- // 没有配置 agent,设置默认值
- record.cpu_info = { value: 0, total: '', used: '' }
- record.memory_info = { value: 0, total: '', used: '' }
- record.disk_info = { value: 0, total: '', used: '' }
+ if (!record.server_identity) {
+ resetMetrics(record)
+ return
+ }
+ try {
+ const response = await fetchServerMetricsSummary(record.server_identity)
+ applyMetricsSummary(record, response.details)
+ } catch (error) {
+ console.warn(`获取服务器 ${record.name} 的监控指标失败:`, error)
+ resetMetrics(record)
}
})
- // 等待所有请求完成
await Promise.all(metricsPromises)
} catch (error) {
console.error('获取所有服务器监控指标失败:', error)
}
}
+const handleCollectNow = async (record: any) => {
+ if (!record.server_identity) {
+ Message.warning('缺少服务器唯一标识,无法采集')
+ return
+ }
+ const key = getCollectingKey(record)
+ if (collectingMap[key]) {
+ return
+ }
+ collectingMap[key] = true
+ try {
+ const response = await collectServerMetricsNow(record.server_identity)
+ if (response.code === 0) {
+ applyMetricsSummary(record, response.details)
+ Message.success('采集完成')
+ } else {
+ Message.error(response.message || '采集失败')
+ }
+ } catch (error) {
+ console.error('立即采集失败:', error)
+ Message.error('采集失败')
+ } finally {
+ collectingMap[key] = false
+ }
+}
+
onMounted(() => {
fetchServers()
})