This commit is contained in:
zxr
2026-04-12 16:40:33 +08:00
parent 1dcab7af96
commit 003c552238
5 changed files with 1269 additions and 853 deletions

View File

@@ -13,6 +13,10 @@ export const fetchAlertRecords = (data: {
keyword?: string,
sort?: string,
order?: string,
binding_id?: number,
resource_category?: string,
server_identity?: string,
ip?: string,
}) => {
return request.get("/Alert/v1/record/list", { params: data });
};

View File

@@ -25,7 +25,7 @@
<a-form-item label="Agent URL配置">
<a-input
v-model="form.agent_config"
placeholder="http://192.168.1.100:9100/dc-host/v1/control/command"
placeholder="http://192.168.1.100:9100/dc-host/stats"
allow-clear
/>
<template #extra>

View File

@@ -16,16 +16,20 @@
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item field="host" label="主机地址" required>
<a-input v-model="formData.host" placeholder="请输入主机地址" />
<a-form-item
field="host"
label="主机地址(IPv4 / IPv6)"
required
>
<a-input v-model="formData.host" placeholder="域名或 IP如 server.example.com 或 192.168.1.10" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="20">
<a-col :span="12">
<a-form-item field="ip_address" label="IP地址">
<a-input v-model="formData.ip_address" placeholder="请输入IP地址" />
<a-form-item field="ip_address" label="IP地址" required>
<a-input v-model="formData.ip_address" placeholder="IPv4 或 IPv6如 192.168.1.10" />
</a-form-item>
</a-col>
</a-row>
@@ -92,7 +96,7 @@
</a-row>
<a-form-item field="agent_config" label="Agent 配置 URL">
<a-input v-model="formData.agent_config" placeholder="http://192.168.1.100:9100/dc-host/v1/control/command" />
<a-input v-model="formData.agent_config" placeholder="http://192.168.1.100:9100/dc-host/stats" />
</a-form-item>
<a-row :gutter="20">
@@ -182,9 +186,79 @@ const formData = reactive<ServerFormData>({
ip_scan_port: 12429,
})
/** 判断是否为合法 IPv4 字符串 */
function isIPv4String(host: string): boolean {
const h = host.trim()
if (!h) return false
const parts = h.split('.')
if (parts.length !== 4) return false
return parts.every((p) => {
if (!/^\d{1,3}$/.test(p)) return false
const n = Number(p)
return n >= 0 && n <= 255
})
}
/**
* 若主机地址为 IP返回规范化后的 IPIPv4 或 IPv6否则返回 null
*/
function extractIpFromHost(host: string): string | null {
const t = host.trim()
if (!t) return null
if (isIPv4String(t)) return t
if (!t.includes(':')) return null
try {
const withBrackets = t.startsWith('[') && t.endsWith(']') ? t : `[${t}]`
const u = new URL(`http://${withBrackets}/`)
if (u.hostname.includes(':')) return u.hostname
} catch {
return null
}
return null
}
/** 校验 IP 地址字段IPv4 或 IPv6 */
function isValidIpAddress(s: string): boolean {
const t = s.trim()
if (!t) return false
if (isIPv4String(t)) return true
try {
const withBrackets = t.startsWith('[') && t.endsWith(']') ? t : `[${t}]`
const u = new URL(`http://${withBrackets}/`)
return u.hostname.includes(':')
} catch {
return false
}
}
/** 主机为 IP 时同步到 IP 地址字段 */
function syncIpFromHost() {
const ip = extractIpFromHost(formData.host)
if (ip) {
formData.ip_address = ip
}
}
const rules = {
name: [{ required: true, message: '请输入服务器名称' }],
host: [{ required: true, message: '请输入主机地址' }],
ip_address: [
{ required: true, message: '请输入IP地址' },
{
validator: (value: string | undefined, cb: (error?: string) => void) => {
const v = (value || '').trim()
if (!v) {
cb()
return
}
if (!isValidIpAddress(v)) {
cb('请输入合法的 IPv4 或 IPv6 地址')
return
}
cb()
},
},
],
}
function validateAgentConfigURL(raw?: string): string | null {
@@ -228,6 +302,7 @@ watch(
is_ip_scan_server: props.record.is_ip_scan_server ?? false,
ip_scan_port: props.record.ip_scan_port || 12429,
})
syncIpFromHost()
} else {
Object.assign(formData, {
server_identity: '',
@@ -255,6 +330,14 @@ watch(
}
)
watch(
() => formData.host,
() => {
if (!props.visible) return
syncIpFromHost()
},
)
const handleOk = async () => {
try {
await formRef.value?.validate()

View File

@@ -460,19 +460,7 @@ const handleDelete = async (record: any) => {
})
}
/** dc-host `/dc-host/v1/control/command` 拉取本机采集指标execute_task + service_collect */
const buildDcHostServiceCollectBody = () => ({
command: 'execute_task' as const,
params: {
task_id: 0,
task_name: 'service_collect',
type: 'host' as const,
config: '{}',
timeout: 120,
},
timestamp: new Date().toISOString(),
})
/** dc-host `GET agent_config`(一般为 `/dc-host/stats`)返回裸 Metrics JSON */
// 获取所有服务器的监控指标
const getAllMetrics = async () => {
try {
@@ -485,9 +473,8 @@ const getAllMetrics = async () => {
let metricsUrl = record.agent_config
// 验证 URL 是否合法
let agentUrl: URL
try {
agentUrl = new URL(metricsUrl)
new URL(metricsUrl)
} catch (urlError) {
console.warn(`服务器 ${record.name} 的 agent_config 不是合法的 URL:`, metricsUrl)
// 设置默认值 0
@@ -496,12 +483,8 @@ const getAllMetrics = async () => {
record.disk_info = { value: 0, total: '', used: '' }
return
}
// dc-host 控制面拉取指标接口为 POST
const isDcHostCommand = agentUrl.pathname.includes('/dc-host/v1/control/command')
// 使用独立的 axios 实例请求外部 agent绕过全局拦截器
const response = isDcHostCommand
? await agentAxios.post(metricsUrl, buildDcHostServiceCollectBody())
: await agentAxios.get(metricsUrl)
const response = await agentAxios.get(metricsUrl)
console.log('获取指标数据:', response.data)
if (response.data) {
// 更新记录的监控数据

File diff suppressed because it is too large Load Diff