This commit is contained in:
2026-04-13 23:18:15 +08:00
parent f030f9c5c9
commit e84cb75dda
3 changed files with 876 additions and 986 deletions

View File

@@ -1,334 +1,317 @@
/**
* 服务器硬件监控页专用:对接 DC-Hardware 服务(/DC-Hardware/v1
* 与「机房设备监控」等业务区分,勿混用命名。
*/
import { request } from '@/api/request'
const HW_PREFIX = '/DC-Hardware/v1'
/** 与 bsm-sdk 成功响应一致:业务数据在 details */
export interface HostHardwareApiEnvelope<T = unknown> {
code?: number | string
message?: string
details?: T
}
export interface HostHardwareDeviceDetailPayload {
device: HostHardwareDevice
status: HostHardwareStatus | null
}
export interface HostHardwareDevice {
id: string
name?: string
ip: string
/** 设备类别,如 server/switch/storage未返回时前端可按 server 展示 */
type?: string
protocol: string
manufacturer?: string
model?: string
serial_number?: string
username?: string
password?: string
port?: number
snmp_port?: number
community?: string
snmp_version?: string
redfish_base_url?: string
redfish_tls_skip_verify?: boolean
ipmi_timeout_seconds?: number
snmp_timeout_seconds?: number
redfish_timeout_seconds?: number
ipmi_collect_enabled?: boolean
snmp_collect_enabled?: boolean
redfish_collect_enabled?: boolean
collect_interval?: number
asset_id?: string
server_identity?: string
enabled?: boolean
status?: string
tags?: string
description?: string
extra_config?: string
}
/** 创建/更新 DC-Hardware 设备(与 CreateDeviceRequest 一致;密码在更新时为空则不修改) */
export interface HostHardwareDeviceUpsert {
name: string
ip: string
/** 省略或空则服务端默认 server */
type?: string
protocol: string
username?: string
password?: string
port?: number
snmp_port?: number
community?: string
snmp_version?: string
redfish_base_url?: string
redfish_tls_skip_verify?: boolean
location?: string
description?: string
tags?: string
asset_id?: string
server_identity?: string
extra_config?: string
ipmi_timeout_seconds?: number
snmp_timeout_seconds?: number
redfish_timeout_seconds?: number
ipmi_collect_enabled?: boolean
snmp_collect_enabled?: boolean
redfish_collect_enabled?: boolean
collect_interval?: number
}
export interface HostHardwareDeviceListPayload {
total: number
page: string | number
page_size: string | number
data: HostHardwareDevice[]
}
export interface HostHardwareStatus {
id?: string
device_id?: string
status?: string
power_status?: string
cpu_status?: string
memory_status?: string
disk_status?: string
fan_status?: string
temperature_status?: string
network_status?: string
psu_status?: string
raid_status?: string
last_check_time?: string
error_message?: string
raw_data?: string
}
export interface HostHardwareMetricsRow {
id?: string
device_id?: string
metric_name: string
metric_type: string
metric_value: number
unit?: string
status?: string
threshold?: number
location?: string
collection_time?: string
}
export interface HostHardwareLatestCollectionPayload {
device_id: string
collected_at?: string | null
status: HostHardwareStatus | null
metrics: HostHardwareMetricsRow[]
timescaledb?: boolean
message?: string
server_identity?: string
}
interface RawCollectionMetric {
name?: string
type?: string
value?: number
unit?: string
status?: string
threshold?: number
location?: string
}
interface RawCollectionRoot {
metrics?: RawCollectionMetric[]
}
export interface NormalizedHostHardwareMetric {
name: string
type: string
value: number
unit: string
status: string
threshold?: number
location?: string
}
export interface HostHardwareMetricHistoryPayload {
device_id: string
metric_name: string
start_time?: string
end_time?: string
data: HostHardwareMetricsRow[]
timescaledb?: boolean
message?: string
}
export interface HostHardwareStatisticsRow {
device_id: string
stat_date: string
online_time?: number
offline_time?: number
warning_count?: number
critical_count?: number
avg_temperature?: number
max_temperature?: number
min_temperature?: number
avg_fan_speed?: number
avg_power_usage?: number
max_power_usage?: number
total_check_count?: number
success_check_count?: number
failed_check_count?: number
availability?: number
}
export function isHostHardwareApiSuccess(res: HostHardwareApiEnvelope | null | undefined): boolean {
const c = res?.code
if (c === 0 || c === '0') return true
// 少数网关/代理以 200 表示业务成功
if (c === 200 || c === '200') return true
return false
}
export function unwrapHostHardwareDetails<T>(
res: (HostHardwareApiEnvelope<T> & { data?: T }) | null | undefined,
): T | null {
if (!res || !isHostHardwareApiSuccess(res)) return null
// 部分网关/SDK 将载荷放在 data 而非 details与 logs 等模块一致做兼容
return res.details ?? res.data ?? null
}
/** 按 server_identity 拉取最新一整轮采集JWT */
export function fetchHostHardwareLatestCollection(serverIdentity: string) {
return request.get<HostHardwareApiEnvelope<HostHardwareLatestCollectionPayload>>(
`${HW_PREFIX}/devices/by-server-identity/collection/latest`,
{ params: { server_identity: serverIdentity } },
)
}
/** 设备详情(含最新一条 status */
export function fetchHostHardwareDevice(deviceId: string) {
return request.get<HostHardwareApiEnvelope<HostHardwareDeviceDetailPayload>>(
`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}`,
)
}
/** 分页列表(可按 type / status / asset_id 筛选) */
export function fetchHostHardwareDeviceList(params?: {
type?: string
status?: string
asset_id?: string
page?: number
page_size?: number
}) {
return request.get<HostHardwareApiEnvelope<HostHardwareDeviceListPayload>>(`${HW_PREFIX}/devices`, {
params,
})
}
/** 创建设备 */
export function createHostHardwareDevice(data: HostHardwareDeviceUpsert) {
return request.post<HostHardwareApiEnvelope<HostHardwareDevice>>(`${HW_PREFIX}/devices`, data)
}
/** 更新设备(全量必填字段;密码留空则不修改) */
export function updateHostHardwareDevice(deviceId: string, data: HostHardwareDeviceUpsert) {
return request.put<HostHardwareApiEnvelope<HostHardwareDevice>>(
`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}`,
data,
)
}
/** 异步立即采集 */
export function triggerHostHardwareCollect(deviceId: string) {
return request.post<HostHardwareApiEnvelope<string>>(`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}/collect`)
}
/** 用监控 */
export function enableHostHardwareDevice(deviceId: string) {
return request.post<HostHardwareApiEnvelope<string>>(`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}/enable`)
}
/** 禁用监控 */
export function disableHostHardwareDevice(deviceId: string) {
return request.post<HostHardwareApiEnvelope<string>>(`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}/disable`)
}
/** 单指标历史曲线JWT */
export function fetchHostHardwareMetricHistory(
deviceId: string,
metricName: string,
startTime?: string,
endTime?: string,
) {
return request.get<HostHardwareApiEnvelope<HostHardwareMetricHistoryPayload>>(
`${HW_PREFIX}/metrics/devices/${encodeURIComponent(deviceId)}/history`,
{
params: {
metric_name: metricName,
...(startTime ? { start_time: startTime } : {}),
...(endTime ? { end_time: endTime } : {}),
},
},
)
}
/** 日汇总统计 */
export function fetchHostHardwareStatistics(
deviceId: string,
startDate?: string,
endDate?: string,
) {
return request.get<HostHardwareApiEnvelope<HostHardwareStatisticsRow[]>>(
`${HW_PREFIX}/metrics/statistics`,
{
params: {
device_id: deviceId,
...(startDate ? { start_date: startDate } : {}),
...(endDate ? { end_date: endDate } : {}),
},
},
)
}
/**
* 合并 API metrics 与 raw_data 兜底(无时序库时 metrics 可能为空)
*/
export function normalizeHostHardwareMetrics(
status: HostHardwareStatus | null | undefined,
metricsFromApi: HostHardwareMetricsRow[] | null | undefined,
): NormalizedHostHardwareMetric[] {
const fromApi = metricsFromApi ?? []
if (fromApi.length > 0) {
return fromApi.map((m) => ({
name: m.metric_name,
type: m.metric_type,
value: m.metric_value,
unit: m.unit ?? '',
status: m.status ?? 'ok',
threshold: m.threshold,
location: m.location,
}))
}
const raw = status?.raw_data
if (!raw || typeof raw !== 'string') return []
try {
const parsed = JSON.parse(raw) as RawCollectionRoot
const arr = parsed.metrics
if (!Array.isArray(arr)) return []
return arr
.map((m) => ({
name: String(m.name ?? ''),
type: String(m.type ?? ''),
value: typeof m.value === 'number' ? m.value : Number(m.value) || 0,
unit: String(m.unit ?? ''),
status: String(m.status ?? 'ok'),
threshold: m.threshold,
location: m.location ? String(m.location) : undefined,
}))
.filter((m) => m.name || m.type)
} catch {
return []
}
}
/**
* 服务器硬件监控页专用:对接 DC-Hardware 服务(/DC-Hardware/v1
* 与「机房设备监控」等业务区分,勿混用命名。
*/
import { request } from '@/api/request'
const HW_PREFIX = '/DC-Hardware/v1'
/** 与 bsm-sdk 成功响应一致:业务数据在 details */
export interface HostHardwareApiEnvelope<T = unknown> {
code?: number | string
message?: string
details?: T
}
export interface HostHardwareDeviceDetailPayload {
device: HostHardwareDevice
status: HostHardwareStatus | null
}
export interface HostHardwareDevice {
id: string
name?: string
ip: string
/** 设备类别,如 server/switch/storage未返回时前端可按 server 展示 */
type?: string
protocol: string
manufacturer?: string
model?: string
serial_number?: string
username?: string
password?: string
port?: number
snmp_port?: number
community?: string
snmp_version?: string
redfish_base_url?: string
redfish_tls_skip_verify?: boolean
ipmi_timeout_seconds?: number
snmp_timeout_seconds?: number
redfish_timeout_seconds?: number
ipmi_collect_enabled?: boolean
snmp_collect_enabled?: boolean
redfish_collect_enabled?: boolean
collect_interval?: number
asset_id?: string
server_identity?: string
enabled?: boolean
status?: string
tags?: string
description?: string
extra_config?: string
}
/** 创建/更新 DC-Hardware 设备(与 CreateDeviceRequest 一致;密码在更新时为空则不修改) */
export interface HostHardwareDeviceUpsert {
name: string
ip: string
/** 省略或空则服务端默认 server */
type?: string
protocol: string
username?: string
password?: string
port?: number
snmp_port?: number
community?: string
snmp_version?: string
redfish_base_url?: string
redfish_tls_skip_verify?: boolean
location?: string
description?: string
tags?: string
asset_id?: string
server_identity?: string
extra_config?: string
ipmi_timeout_seconds?: number
snmp_timeout_seconds?: number
redfish_timeout_seconds?: number
ipmi_collect_enabled?: boolean
snmp_collect_enabled?: boolean
redfish_collect_enabled?: boolean
collect_interval?: number
/** 是否启用监控调度 */
enabled?: boolean
}
export interface HostHardwareDeviceListPayload {
total: number
page: string | number
page_size: string | number
data: HostHardwareDevice[]
}
export interface HostHardwareStatus {
id?: string
device_id?: string
status?: string
power_status?: string
cpu_status?: string
memory_status?: string
disk_status?: string
fan_status?: string
temperature_status?: string
network_status?: string
psu_status?: string
raid_status?: string
last_check_time?: string
error_message?: string
raw_data?: string
}
export interface HostHardwareMetricsRow {
id?: string
device_id?: string
metric_name: string
metric_type: string
metric_value: number
unit?: string
status?: string
threshold?: number
location?: string
collection_time?: string
}
export interface HostHardwareLatestCollectionPayload {
device_id: string
collected_at?: string | null
status: HostHardwareStatus | null
metrics: HostHardwareMetricsRow[]
timescaledb?: boolean
message?: string
server_identity?: string
}
interface RawCollectionMetric {
name?: string
type?: string
value?: number
unit?: string
status?: string
threshold?: number
location?: string
}
interface RawCollectionRoot {
metrics?: RawCollectionMetric[]
}
export interface NormalizedHostHardwareMetric {
name: string
type: string
value: number
unit: string
status: string
threshold?: number
location?: string
}
export interface HostHardwareMetricHistoryPayload {
device_id: string
metric_name: string
start_time?: string
end_time?: string
data: HostHardwareMetricsRow[]
timescaledb?: boolean
message?: string
}
export interface HostHardwareStatisticsRow {
device_id: string
stat_date: string
online_time?: number
offline_time?: number
warning_count?: number
critical_count?: number
avg_temperature?: number
max_temperature?: number
min_temperature?: number
avg_fan_speed?: number
avg_power_usage?: number
max_power_usage?: number
total_check_count?: number
success_check_count?: number
failed_check_count?: number
availability?: number
}
export function isHostHardwareApiSuccess(res: HostHardwareApiEnvelope | null | undefined): boolean {
const c = res?.code
if (c === 0 || c === '0') return true
// 少数网关/代理以 200 表示业务成功
if (c === 200 || c === '200') return true
return false
}
export function unwrapHostHardwareDetails<T>(res: (HostHardwareApiEnvelope<T> & { data?: T }) | null | undefined): T | null {
if (!res || !isHostHardwareApiSuccess(res)) return null
// 部分网关/SDK 将载荷放在 data 而非 details与 logs 等模块一致做兼容
return res.details ?? res.data ?? null
}
/** 按 server_identity 拉取最新一整轮采集JWT */
export function fetchHostHardwareLatestCollection(serverIdentity: string) {
return request.get<HostHardwareApiEnvelope<HostHardwareLatestCollectionPayload>>(
`${HW_PREFIX}/devices/by-server-identity/collection/latest`,
{ params: { server_identity: serverIdentity } }
)
}
/** 设备详情(含最新一条 status */
export function fetchHostHardwareDevice(deviceId: string) {
return request.get<HostHardwareApiEnvelope<HostHardwareDeviceDetailPayload>>(`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}`)
}
/** 分页列表(可按 type / status / asset_id 筛选) */
export function fetchHostHardwareDeviceList(params?: {
type?: string
status?: string
asset_id?: string
page?: number
page_size?: number
}) {
return request.get<HostHardwareApiEnvelope<HostHardwareDeviceListPayload>>(`${HW_PREFIX}/devices`, {
params,
})
}
/** 创建设备 */
export function createHostHardwareDevice(data: HostHardwareDeviceUpsert) {
return request.post<HostHardwareApiEnvelope<HostHardwareDevice>>(`${HW_PREFIX}/devices`, data)
}
/** 更新设备(全量必填字段;密码留空则不修改) */
export function updateHostHardwareDevice(deviceId: string, data: HostHardwareDeviceUpsert) {
return request.put<HostHardwareApiEnvelope<HostHardwareDevice>>(`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}`, data)
}
/** 异步立即采集 */
export function triggerHostHardwareCollect(deviceId: string) {
return request.post<HostHardwareApiEnvelope<string>>(`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}/collect`)
}
/** 启用监控 */
export function enableHostHardwareDevice(deviceId: string) {
return request.post<HostHardwareApiEnvelope<string>>(`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}/enable`)
}
/** 用监控 */
export function disableHostHardwareDevice(deviceId: string) {
return request.post<HostHardwareApiEnvelope<string>>(`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}/disable`)
}
/** 单指标历史曲线JWT */
export function fetchHostHardwareMetricHistory(deviceId: string, metricName: string, startTime?: string, endTime?: string) {
return request.get<HostHardwareApiEnvelope<HostHardwareMetricHistoryPayload>>(
`${HW_PREFIX}/metrics/devices/${encodeURIComponent(deviceId)}/history`,
{
params: {
metric_name: metricName,
...(startTime ? { start_time: startTime } : {}),
...(endTime ? { end_time: endTime } : {}),
},
}
)
}
/** 日汇总统计 */
export function fetchHostHardwareStatistics(deviceId: string, startDate?: string, endDate?: string) {
return request.get<HostHardwareApiEnvelope<HostHardwareStatisticsRow[]>>(`${HW_PREFIX}/metrics/statistics`, {
params: {
device_id: deviceId,
...(startDate ? { start_date: startDate } : {}),
...(endDate ? { end_date: endDate } : {}),
},
})
}
/**
* 合并 API metrics 与 raw_data 兜底(无时序库时 metrics 可能为空)
*/
export function normalizeHostHardwareMetrics(
status: HostHardwareStatus | null | undefined,
metricsFromApi: HostHardwareMetricsRow[] | null | undefined
): NormalizedHostHardwareMetric[] {
const fromApi = metricsFromApi ?? []
if (fromApi.length > 0) {
return fromApi.map((m) => ({
name: m.metric_name,
type: m.metric_type,
value: m.metric_value,
unit: m.unit ?? '',
status: m.status ?? 'ok',
threshold: m.threshold,
location: m.location,
}))
}
const raw = status?.raw_data
if (!raw || typeof raw !== 'string') return []
try {
const parsed = JSON.parse(raw) as RawCollectionRoot
const arr = parsed.metrics
if (!Array.isArray(arr)) return []
return arr
.map((m) => ({
name: String(m.name ?? ''),
type: String(m.type ?? ''),
value: typeof m.value === 'number' ? m.value : Number(m.value) || 0,
unit: String(m.unit ?? ''),
status: String(m.status ?? 'ok'),
threshold: m.threshold,
location: m.location ? String(m.location) : undefined,
}))
.filter((m) => m.name || m.type)
} catch {
return []
}
}

File diff suppressed because one or more lines are too long