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

@@ -80,6 +80,8 @@ export interface HostHardwareDeviceUpsert {
snmp_collect_enabled?: boolean snmp_collect_enabled?: boolean
redfish_collect_enabled?: boolean redfish_collect_enabled?: boolean
collect_interval?: number collect_interval?: number
/** 是否启用监控调度 */
enabled?: boolean
} }
export interface HostHardwareDeviceListPayload { export interface HostHardwareDeviceListPayload {
@@ -191,9 +193,7 @@ export function isHostHardwareApiSuccess(res: HostHardwareApiEnvelope | null | u
return false return false
} }
export function unwrapHostHardwareDetails<T>( export function unwrapHostHardwareDetails<T>(res: (HostHardwareApiEnvelope<T> & { data?: T }) | null | undefined): T | null {
res: (HostHardwareApiEnvelope<T> & { data?: T }) | null | undefined,
): T | null {
if (!res || !isHostHardwareApiSuccess(res)) return null if (!res || !isHostHardwareApiSuccess(res)) return null
// 部分网关/SDK 将载荷放在 data 而非 details与 logs 等模块一致做兼容 // 部分网关/SDK 将载荷放在 data 而非 details与 logs 等模块一致做兼容
return res.details ?? res.data ?? null return res.details ?? res.data ?? null
@@ -203,15 +203,13 @@ export function unwrapHostHardwareDetails<T>(
export function fetchHostHardwareLatestCollection(serverIdentity: string) { export function fetchHostHardwareLatestCollection(serverIdentity: string) {
return request.get<HostHardwareApiEnvelope<HostHardwareLatestCollectionPayload>>( return request.get<HostHardwareApiEnvelope<HostHardwareLatestCollectionPayload>>(
`${HW_PREFIX}/devices/by-server-identity/collection/latest`, `${HW_PREFIX}/devices/by-server-identity/collection/latest`,
{ params: { server_identity: serverIdentity } }, { params: { server_identity: serverIdentity } }
) )
} }
/** 设备详情(含最新一条 status */ /** 设备详情(含最新一条 status */
export function fetchHostHardwareDevice(deviceId: string) { export function fetchHostHardwareDevice(deviceId: string) {
return request.get<HostHardwareApiEnvelope<HostHardwareDeviceDetailPayload>>( return request.get<HostHardwareApiEnvelope<HostHardwareDeviceDetailPayload>>(`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}`)
`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}`,
)
} }
/** 分页列表(可按 type / status / asset_id 筛选) */ /** 分页列表(可按 type / status / asset_id 筛选) */
@@ -234,10 +232,7 @@ export function createHostHardwareDevice(data: HostHardwareDeviceUpsert) {
/** 更新设备(全量必填字段;密码留空则不修改) */ /** 更新设备(全量必填字段;密码留空则不修改) */
export function updateHostHardwareDevice(deviceId: string, data: HostHardwareDeviceUpsert) { export function updateHostHardwareDevice(deviceId: string, data: HostHardwareDeviceUpsert) {
return request.put<HostHardwareApiEnvelope<HostHardwareDevice>>( return request.put<HostHardwareApiEnvelope<HostHardwareDevice>>(`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}`, data)
`${HW_PREFIX}/devices/${encodeURIComponent(deviceId)}`,
data,
)
} }
/** 异步立即采集 */ /** 异步立即采集 */
@@ -256,12 +251,7 @@ export function disableHostHardwareDevice(deviceId: string) {
} }
/** 单指标历史曲线JWT */ /** 单指标历史曲线JWT */
export function fetchHostHardwareMetricHistory( export function fetchHostHardwareMetricHistory(deviceId: string, metricName: string, startTime?: string, endTime?: string) {
deviceId: string,
metricName: string,
startTime?: string,
endTime?: string,
) {
return request.get<HostHardwareApiEnvelope<HostHardwareMetricHistoryPayload>>( return request.get<HostHardwareApiEnvelope<HostHardwareMetricHistoryPayload>>(
`${HW_PREFIX}/metrics/devices/${encodeURIComponent(deviceId)}/history`, `${HW_PREFIX}/metrics/devices/${encodeURIComponent(deviceId)}/history`,
{ {
@@ -270,26 +260,19 @@ export function fetchHostHardwareMetricHistory(
...(startTime ? { start_time: startTime } : {}), ...(startTime ? { start_time: startTime } : {}),
...(endTime ? { end_time: endTime } : {}), ...(endTime ? { end_time: endTime } : {}),
}, },
}, }
) )
} }
/** 日汇总统计 */ /** 日汇总统计 */
export function fetchHostHardwareStatistics( export function fetchHostHardwareStatistics(deviceId: string, startDate?: string, endDate?: string) {
deviceId: string, return request.get<HostHardwareApiEnvelope<HostHardwareStatisticsRow[]>>(`${HW_PREFIX}/metrics/statistics`, {
startDate?: string, params: {
endDate?: string, device_id: deviceId,
) { ...(startDate ? { start_date: startDate } : {}),
return request.get<HostHardwareApiEnvelope<HostHardwareStatisticsRow[]>>( ...(endDate ? { end_date: endDate } : {}),
`${HW_PREFIX}/metrics/statistics`,
{
params: {
device_id: deviceId,
...(startDate ? { start_date: startDate } : {}),
...(endDate ? { end_date: endDate } : {}),
},
}, },
) })
} }
/** /**
@@ -297,7 +280,7 @@ export function fetchHostHardwareStatistics(
*/ */
export function normalizeHostHardwareMetrics( export function normalizeHostHardwareMetrics(
status: HostHardwareStatus | null | undefined, status: HostHardwareStatus | null | undefined,
metricsFromApi: HostHardwareMetricsRow[] | null | undefined, metricsFromApi: HostHardwareMetricsRow[] | null | undefined
): NormalizedHostHardwareMetric[] { ): NormalizedHostHardwareMetric[] {
const fromApi = metricsFromApi ?? [] const fromApi = metricsFromApi ?? []
if (fromApi.length > 0) { if (fromApi.length > 0) {

View File

@@ -11,208 +11,171 @@
unmount-on-close unmount-on-close
@ok="handleSubmit" @ok="handleSubmit"
@cancel="handleCancel" @cancel="handleCancel"
@update:visible="(v: boolean) => emit('update:visible', v)"
> >
<div class="modal-scroll"> <div class="modal-scroll">
<a-spin :loading="loading" style="width: 100%; min-height: 200px"> <a-spin :loading="loading" style="width: 98%; margin: 0 auto; min-height: 200px">
<div v-if="!loading && blockedNoIdentity" class="blocked-wrap"> <div v-if="!loading && blockedNoIdentity" class="blocked-wrap">
<a-alert type="warning" show-icon> <a-alert type="warning" show-icon>
当前服务器未配置唯一标识请先在编辑服务器中填写并保存以便与 DC-Hardware 带外设备关联 当前服务器未配置唯一标识请先在编辑服务器中填写并保存以便与 DC-Hardware 带外设备关联
</a-alert> </a-alert>
</div> </div>
<template v-else-if="!loading"> <template v-else-if="!loading">
<a-form ref="formRef" :model="form" :rules="rules" layout="vertical">
<a-divider orientation="left">基础信息</a-divider>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="管理 IPBMC / 带外)">
<span class="readonly-field">{{ managementIp || '—' }}</span>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item field="collect_interval" label="采集间隔(秒)">
<a-input-number v-model="form.collect_interval" :min="0" style="width: 100%" />
<template #extra>
<span class="form-extra">0 或留空表示使用服务默认间隔</span>
</template>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item field="description" label="备注">
<a-textarea v-model="form.description" :rows="2" placeholder="可选" allow-clear />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item field="tags" label="标签">
<a-input v-model="form.tags" placeholder="可为 JSON 字符串,如实体传感器配置等" allow-clear />
</a-form-item>
</a-col>
</a-row>
<a-divider orientation="left">采集协议与连接</a-divider>
<a-form ref="formRef" :model="form" :rules="rules" layout="vertical"> <a-form-item field="protocol" label="协议" required>
<a-collapse :default-active-key="['base', 'proto', 'collect']" :bordered="false"> <a-radio-group :model-value="form.protocol" type="button" @update:model-value="onProtocolModelUpdate">
<a-collapse-item key="base" header="基础信息"> <a-radio value="ipmi">IPMI</a-radio>
<a-row :gutter="16"> <a-radio value="snmp">SNMP</a-radio>
<a-col :span="24"> <a-radio value="redfish">Redfish</a-radio>
<a-form-item label="管理 IPBMC / 带外)"> </a-radio-group>
<span class="readonly-field">{{ managementIp || '—' }}</span> <template #extra>
</a-form-item> <span class="form-extra">切换协议后请填写对应区域的认证与端口默认值IPMI 623SNMP 161</span>
</a-col>
<a-col :span="24">
<a-form-item field="description" label="备注">
<a-textarea v-model="form.description" :rows="2" placeholder="可选" allow-clear />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item field="tags" label="标签">
<a-input v-model="form.tags" placeholder="可为 JSON 字符串,如实体传感器配置等" allow-clear />
</a-form-item>
</a-col>
</a-row>
</a-collapse-item>
<a-collapse-item key="proto" header="采集协议与连接">
<a-form-item field="protocol" label="协议" required>
<a-radio-group
:model-value="form.protocol"
type="button"
@update:model-value="onProtocolModelUpdate"
>
<a-radio value="ipmi">IPMI</a-radio>
<a-radio value="snmp">SNMP</a-radio>
<a-radio value="redfish">Redfish</a-radio>
</a-radio-group>
<template #extra>
<span class="form-extra">切换协议后请填写对应区域的认证与端口默认值IPMI 623SNMP 161</span>
</template>
</a-form-item>
<!-- IPMI / Redfish 共用账号 -->
<template v-if="form.protocol === 'ipmi' || form.protocol === 'redfish'">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item field="username" label="用户名">
<a-input v-model="form.username" placeholder="BMC 用户名" allow-clear />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item field="password" label="密码">
<a-input-password v-model="form.password" :placeholder="passwordPlaceholder" allow-clear />
<template #extra>
<span class="form-extra">{{ passwordHint }}</span>
</template>
</a-form-item>
</a-col>
</a-row>
</template> </template>
</a-form-item>
<template v-if="form.protocol === 'ipmi'"> <template v-if="form.protocol === 'ipmi' || form.protocol === 'redfish'">
<a-row :gutter="16">
<a-col :span="8">
<a-form-item field="port" label="IPMI 端口">
<a-input-number v-model="form.port" :min="1" :max="65535" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item field="ipmi_timeout_seconds" label="超时(秒)">
<a-input-number v-model="form.ipmi_timeout_seconds" :min="0" style="width: 100%" />
<template #extra><span class="form-extra">0 表示使用服务默认</span></template>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="启用 IPMI 采集">
<a-switch v-model="form.ipmi_collect_enabled" />
</a-form-item>
</a-col>
</a-row>
</template>
<template v-if="form.protocol === 'snmp'">
<a-row :gutter="16">
<a-col :span="8">
<a-form-item field="snmp_port" label="SNMP 端口">
<a-input-number v-model="form.snmp_port" :min="1" :max="65535" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item field="snmp_version" label="SNMP 版本">
<a-select v-model="form.snmp_version" allow-clear>
<a-option value="v2c">v2c</a-option>
<a-option value="v1">v1</a-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item field="snmp_timeout_seconds" label="超时(秒)">
<a-input-number v-model="form.snmp_timeout_seconds" :min="0" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item field="community" label="Community 共享口令">
<a-input v-model="form.community" placeholder="v2c Community" allow-clear />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="启用 SNMP 采集">
<a-switch v-model="form.snmp_collect_enabled" />
</a-form-item>
</a-col>
</a-row>
</template>
<template v-if="form.protocol === 'redfish'">
<a-row :gutter="16">
<a-col :span="24">
<a-form-item field="redfish_base_url" label="Redfish 根 URL">
<a-input
v-model="form.redfish_base_url"
placeholder="留空则默认 https://{管理IP}/redfish/v1"
allow-clear
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="跳过 TLS 校验">
<a-switch v-model="form.redfish_tls_skip_verify" />
<template #extra><span class="form-extra">仅内网测试环境建议开启</span></template>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item field="redfish_timeout_seconds" label="超时(秒)">
<a-input-number v-model="form.redfish_timeout_seconds" :min="0" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="启用 Redfish 采集">
<a-switch v-model="form.redfish_collect_enabled" />
</a-form-item>
</a-col>
</a-row>
</template>
</a-collapse-item>
<a-collapse-item key="collect" header="采集调度与扩展">
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :span="12"> <a-col :span="12">
<a-form-item field="collect_interval" label="采集间隔(秒)"> <a-form-item field="username" label="用户名">
<a-input-number v-model="form.collect_interval" :min="0" style="width: 100%" /> <a-input v-model="form.username" placeholder="BMC 用户名" allow-clear />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item field="password" label="密码">
<a-input-password v-model="form.password" :placeholder="passwordPlaceholder" allow-clear />
<template #extra> <template #extra>
<span class="form-extra">0 或留空表示使用服务默认间隔YAML</span> <span class="form-extra">{{ passwordHint }}</span>
</template> </template>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col v-if="isEdit && hwEnabled !== undefined" :span="12"> </a-row>
<a-form-item label="监控开关(只读)"> </template>
<a-space>
<a-tag :color="hwEnabled ? 'green' : 'gray'">{{ hwEnabled ? '已启用' : '已禁用' }}</a-tag> <template v-if="form.protocol === 'ipmi'">
<span class="form-extra">保存后可用下方快捷操作切换</span> <a-row :gutter="16">
</a-space> <a-col :span="8">
<a-form-item field="port" label="IPMI 端口">
<a-input-number v-model="form.port" :min="1" :max="65535" style="width: 100%" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="24"> <a-col :span="8">
<a-form-item field="extra_config" label="扩展配置JSON 字符串"> <a-form-item field="ipmi_timeout_seconds" label="超时(秒">
<a-textarea <a-input-number v-model="form.ipmi_timeout_seconds" :min="0" style="width: 100%" />
v-model="form.extra_config" <template #extra><span class="form-extra">0 表示使用服务默认</span></template>
:rows="4" </a-form-item>
placeholder='可选,非空须为合法 JSON如 {"key":"value"}' </a-col>
allow-clear <a-col :span="8">
/> <a-form-item label="启用 IPMI 采集">
<a-switch v-model="form.ipmi_collect_enabled" />
</a-form-item> </a-form-item>
</a-col> </a-col>
</a-row> </a-row>
</a-collapse-item> </template>
</a-collapse>
<a-divider v-if="isEdit && deviceId" orientation="left">快捷操作</a-divider> <template v-if="form.protocol === 'snmp'">
<a-space v-if="isEdit && deviceId" wrap> <a-row :gutter="16">
<a-button type="outline" :loading="actionLoading === 'collect'" @click="doCollect"> <a-col :span="8">
立即采集 <a-form-item field="snmp_port" label="SNMP 端口">
</a-button> <a-input-number v-model="form.snmp_port" :min="1" :max="65535" style="width: 100%" />
<a-button v-if="!hwEnabled" type="outline" status="success" :loading="actionLoading === 'enable'" @click="doEnable"> </a-form-item>
启用监控 </a-col>
</a-button> <a-col :span="8">
<a-button v-else type="outline" status="warning" :loading="actionLoading === 'disable'" @click="doDisable"> <a-form-item field="snmp_version" label="SNMP 版本">
禁用监控 <a-select v-model="form.snmp_version" allow-clear>
</a-button> <a-option value="v2c">v2c</a-option>
</a-space> <a-option value="v1">v1</a-option>
</a-form> </a-select>
</template> </a-form-item>
</a-spin> </a-col>
<a-col :span="8">
<a-form-item field="snmp_timeout_seconds" label="超时(秒)">
<a-input-number v-model="form.snmp_timeout_seconds" :min="0" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item field="community" label="Community 共享口令">
<a-input v-model="form.community" placeholder="v2c Community" allow-clear />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="启用 SNMP 采集">
<a-switch v-model="form.snmp_collect_enabled" />
</a-form-item>
</a-col>
</a-row>
</template>
<template v-if="form.protocol === 'redfish'">
<a-row :gutter="16">
<a-col :span="24">
<a-form-item field="redfish_base_url" label="Redfish 根 URL">
<a-input v-model="form.redfish_base_url" placeholder="留空则默认 https://{管理IP}/redfish/v1" allow-clear />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="跳过 TLS 校验">
<a-switch v-model="form.redfish_tls_skip_verify" />
<template #extra><span class="form-extra">仅内网测试环境建议开启</span></template>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item field="redfish_timeout_seconds" label="超时(秒)">
<a-input-number v-model="form.redfish_timeout_seconds" :min="0" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="启用 Redfish 采集">
<a-switch v-model="form.redfish_collect_enabled" />
</a-form-item>
</a-col>
</a-row>
</template>
<a-divider orientation="left">扩展配置</a-divider>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="启用监控">
<a-switch v-model="form.enabled" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item field="extra_config" label="扩展配置JSON 字符串)">
<a-textarea v-model="form.extra_config" :rows="4" placeholder='可选,非空须为合法 JSON如 {"key":"value"}' allow-clear />
</a-form-item>
</a-col>
</a-row>
</a-form>
</template>
</a-spin>
</div> </div>
</a-modal> </a-modal>
</template> </template>
@@ -228,9 +191,6 @@ import {
fetchHostHardwareDeviceList, fetchHostHardwareDeviceList,
createHostHardwareDevice, createHostHardwareDevice,
updateHostHardwareDevice, updateHostHardwareDevice,
triggerHostHardwareCollect,
enableHostHardwareDevice,
disableHostHardwareDevice,
isHostHardwareApiSuccess, isHostHardwareApiSuccess,
unwrapHostHardwareDetails, unwrapHostHardwareDetails,
type HostHardwareDevice, type HostHardwareDevice,
@@ -250,8 +210,6 @@ const loading = ref(false)
const submitLoading = ref(false) const submitLoading = ref(false)
const blockedNoIdentity = ref(false) const blockedNoIdentity = ref(false)
const deviceId = ref<string | null>(null) const deviceId = ref<string | null>(null)
const hwEnabled = ref<boolean | undefined>(undefined)
const actionLoading = ref<'collect' | 'enable' | 'disable' | ''>('')
/** 防止多次触发 loadHardware 时,较早返回的请求覆盖用户已切换的协议/表单 */ /** 防止多次触发 loadHardware 时,较早返回的请求覆盖用户已切换的协议/表单 */
let hardwareLoadGeneration = 0 let hardwareLoadGeneration = 0
@@ -285,13 +243,9 @@ const managementIp = computed(() => {
const hardwareType = ref('server') const hardwareType = ref('server')
const hardwareAssetId = ref('') const hardwareAssetId = ref('')
const passwordPlaceholder = computed(() => const passwordPlaceholder = computed(() => (isEdit.value ? '留空则不修改已保存的密码' : 'BMC / Redfish 密码'))
isEdit.value ? '留空则不修改已保存的密码' : 'BMC / Redfish 密码',
)
const passwordHint = computed(() => const passwordHint = computed(() => (isEdit.value ? '编辑时留空将保留原密码' : '按机房安全要求妥善保管'))
isEdit.value ? '编辑时留空将保留原密码' : '按机房安全要求妥善保管',
)
const form = reactive({ const form = reactive({
protocol: 'ipmi' as 'ipmi' | 'snmp' | 'redfish', protocol: 'ipmi' as 'ipmi' | 'snmp' | 'redfish',
@@ -313,6 +267,7 @@ const form = reactive({
snmp_collect_enabled: true, snmp_collect_enabled: true,
redfish_collect_enabled: true, redfish_collect_enabled: true,
collect_interval: 0, collect_interval: 0,
enabled: true,
}) })
const rules: Record<string, FieldRule | FieldRule[]> = { const rules: Record<string, FieldRule | FieldRule[]> = {
@@ -341,6 +296,7 @@ function resetForm() {
form.snmp_collect_enabled = true form.snmp_collect_enabled = true
form.redfish_collect_enabled = true form.redfish_collect_enabled = true
form.collect_interval = 0 form.collect_interval = 0
form.enabled = true
} }
function applyFromServer(r: ServerItem) { function applyFromServer(r: ServerItem) {
@@ -372,7 +328,7 @@ function applyFromDevice(d: HostHardwareDevice) {
form.snmp_collect_enabled = d.snmp_collect_enabled !== false form.snmp_collect_enabled = d.snmp_collect_enabled !== false
form.redfish_collect_enabled = d.redfish_collect_enabled !== false form.redfish_collect_enabled = d.redfish_collect_enabled !== false
form.collect_interval = d.collect_interval ?? 0 form.collect_interval = d.collect_interval ?? 0
hwEnabled.value = d.enabled form.enabled = d.enabled !== false
} }
function validateExtraConfigJson(): boolean { function validateExtraConfigJson(): boolean {
@@ -417,6 +373,7 @@ function buildPayload(): HostHardwareDeviceUpsert {
snmp_collect_enabled: form.snmp_collect_enabled, snmp_collect_enabled: form.snmp_collect_enabled,
redfish_collect_enabled: form.redfish_collect_enabled, redfish_collect_enabled: form.redfish_collect_enabled,
collect_interval: form.collect_interval, collect_interval: form.collect_interval,
enabled: form.enabled,
} }
const pw = form.password?.trim() const pw = form.password?.trim()
if (pw) { if (pw) {
@@ -454,7 +411,6 @@ async function loadDeviceByServerIdentityFallback(sid: string, gen: number): Pro
async function loadHardware() { async function loadHardware() {
const gen = ++hardwareLoadGeneration const gen = ++hardwareLoadGeneration
deviceId.value = null deviceId.value = null
hwEnabled.value = undefined
blockedNoIdentity.value = false blockedNoIdentity.value = false
if (!props.record) { if (!props.record) {
return return
@@ -474,6 +430,7 @@ async function loadHardware() {
if (isHostHardwareApiSuccess(colRes)) { if (isHostHardwareApiSuccess(colRes)) {
const col = unwrapHostHardwareDetails(colRes) const col = unwrapHostHardwareDetails(colRes)
const did = col?.device_id const did = col?.device_id
deviceId.value = col?.device_id
if (did) { if (did) {
const detailOk = await loadDeviceDetailIntoForm(did, gen) const detailOk = await loadDeviceDetailIntoForm(did, gen)
if (gen !== hardwareLoadGeneration) return if (gen !== hardwareLoadGeneration) return
@@ -516,7 +473,7 @@ watch(
deviceId.value = null deviceId.value = null
blockedNoIdentity.value = false blockedNoIdentity.value = false
} }
}, }
) )
async function handleSubmit() { async function handleSubmit() {
@@ -531,6 +488,7 @@ async function handleSubmit() {
if (!validateExtraConfigJson()) return if (!validateExtraConfigJson()) return
const r = props.record const r = props.record
console.log('r,', r)
if (!(r?.name || '').trim()) { if (!(r?.name || '').trim()) {
Message.error('服务器名称为空,请先在编辑服务器中填写名称') Message.error('服务器名称为空,请先在编辑服务器中填写名称')
return return
@@ -541,13 +499,14 @@ async function handleSubmit() {
} }
submitLoading.value = true submitLoading.value = true
console.log('deviceId.value,', deviceId.value)
try { try {
const payload = buildPayload() const payload = buildPayload()
let res: { code?: number | string; message?: string } let res: { code?: number | string; message?: string }
if (deviceId.value) { if (deviceId.value) {
res = await updateHostHardwareDevice(deviceId.value, payload) as typeof res res = (await updateHostHardwareDevice(deviceId.value, payload)) as typeof res
} else { } else {
res = await createHostHardwareDevice(payload) as typeof res res = (await createHostHardwareDevice(payload)) as typeof res
} }
if (isHostHardwareApiSuccess(res)) { if (isHostHardwareApiSuccess(res)) {
Message.success(deviceId.value ? '修改成功' : '保存成功') Message.success(deviceId.value ? '修改成功' : '保存成功')
@@ -557,8 +516,9 @@ async function handleSubmit() {
Message.error((res as { message?: string }).message || '保存失败') Message.error((res as { message?: string }).message || '保存失败')
} }
} catch (e: unknown) { } catch (e: unknown) {
const msg = (e as { response?: { data?: { message?: string } }; message?: string })?.response?.data?.message const msg =
|| (e as { message?: string })?.message (e as { response?: { data?: { message?: string } }; message?: string })?.response?.data?.message ||
(e as { message?: string })?.message
Message.error(msg || '保存失败') Message.error(msg || '保存失败')
} finally { } finally {
submitLoading.value = false submitLoading.value = false
@@ -568,59 +528,6 @@ async function handleSubmit() {
function handleCancel() { function handleCancel() {
emit('update:visible', false) emit('update:visible', false)
} }
async function doCollect() {
if (!deviceId.value) return
actionLoading.value = 'collect'
try {
const res = await triggerHostHardwareCollect(deviceId.value)
if (isHostHardwareApiSuccess(res)) {
Message.success('采集任务已启动')
} else {
Message.error((res as { message?: string }).message || '操作失败')
}
} catch {
Message.error('请求失败')
} finally {
actionLoading.value = ''
}
}
async function doEnable() {
if (!deviceId.value) return
actionLoading.value = 'enable'
try {
const res = await enableHostHardwareDevice(deviceId.value)
if (isHostHardwareApiSuccess(res)) {
Message.success('已启用监控')
hwEnabled.value = true
} else {
Message.error((res as { message?: string }).message || '操作失败')
}
} catch {
Message.error('请求失败')
} finally {
actionLoading.value = ''
}
}
async function doDisable() {
if (!deviceId.value) return
actionLoading.value = 'disable'
try {
const res = await disableHostHardwareDevice(deviceId.value)
if (isHostHardwareApiSuccess(res)) {
Message.success('已禁用监控')
hwEnabled.value = false
} else {
Message.error((res as { message?: string }).message || '操作失败')
}
} catch {
Message.error('请求失败')
} finally {
actionLoading.value = ''
}
}
</script> </script>
<script lang="ts"> <script lang="ts">

File diff suppressed because one or more lines are too long