fix: validate and normalize disk monitor targets

This commit is contained in:
2026-04-22 23:20:51 +08:00
parent edf0af7953
commit e1cb4fb694
2 changed files with 57 additions and 16 deletions

View File

@@ -45,7 +45,14 @@ import DiskMonitorPolicyForm from './components/DiskMonitorPolicyForm.vue'
import DiskMonitorSummary from './components/DiskMonitorSummary.vue'
import DiskMonitorTargetDialog from './components/DiskMonitorTargetDialog.vue'
import DiskMonitorTargetTable from './components/DiskMonitorTargetTable.vue'
import { createDefaultPolicy, createEmptyTarget, validatePolicy, validateTarget } from './utils/form'
import {
createDefaultPolicy,
createEmptyTarget,
normalizeTargetItem,
validatePolicy,
validateTarget,
validateTargetNotifications
} from './utils/form'
defineOptions({
name: 'DiskMonitorPage'
@@ -71,11 +78,14 @@ const handleBack = async () => {
await router.push('/systemMonitor')
}
const cloneTarget = (target: DiskMonitor.TargetItem): DiskMonitor.TargetItem => ({
...target,
notifyPathList: target.notifyPathList.map(item => ({ ...item })),
notifyHttpList: target.notifyHttpList.map(item => ({ ...item }))
})
const cloneTarget = (target: DiskMonitor.TargetItem): DiskMonitor.TargetItem => {
const normalized = normalizeTargetItem(target)
return {
...normalized,
notifyPathList: normalized.notifyPathList.map(item => ({ ...item })),
notifyHttpList: normalized.notifyHttpList.map(item => ({ ...item }))
}
}
const openAddTarget = () => {
editingTargetIndex.value = -1
@@ -86,23 +96,30 @@ const openAddTarget = () => {
const openEditTarget = (row: DiskMonitor.TargetItem, index: number) => {
editingTargetIndex.value = index
// 编辑时克隆当前行,避免未确认前直接污染列表数据
editingTarget.value = cloneTarget(row)
editingTarget.value = cloneTarget(normalizeTargetItem(row))
targetDialogVisible.value = true
}
const confirmTarget = () => {
// 提交前统一规范盘符并做去重、阈值关系校验
// 提交前统一规范盘符并做去重、阈值与通知配置校验
const normalizedDriveLetter = editingTarget.value.driveLetter.trim().toUpperCase()
const payload: DiskMonitor.TargetItem = {
...editingTarget.value,
...normalizeTargetItem(editingTarget.value),
driveLetter: normalizedDriveLetter
}
const exists = targetList.value
.filter((_, index) => index !== editingTargetIndex.value)
.map(item => item.driveLetter.trim().toUpperCase())
const errorMessage = validateTarget(payload, exists)
if (errorMessage) {
ElMessage.warning(errorMessage)
const targetErrorMessage = validateTarget(payload, exists)
if (targetErrorMessage) {
ElMessage.warning(targetErrorMessage)
return
}
const notifyErrorMessage = validateTargetNotifications(payload)
if (notifyErrorMessage) {
ElMessage.warning(notifyErrorMessage)
return
}
@@ -125,7 +142,8 @@ const loadPolicyDetail = async () => {
if (!detail) return
policyForm.value = detail.policy || createDefaultPolicy()
targetList.value = detail.targets || []
// 后端列表字段允许为空,这里统一归一化为数组,避免编辑器和克隆流程出现空引用
targetList.value = (detail.targets || []).map(item => normalizeTargetItem(item))
}
const loadLatestJob = async () => {
@@ -144,7 +162,7 @@ const loadLatestJob = async () => {
const loadPageData = async () => {
loading.init = true
try {
// 页面初始化时并行拉取策略和最近任务,保证摘要卡片和表单状态一致
// 页面初始化时并行拉取策略和最近任务,保证摘要卡片和表单状态一致
await Promise.all([loadPolicyDetail(), loadLatestJob()])
} finally {
loading.init = false
@@ -167,7 +185,7 @@ const handleSave = async () => {
targets: targetList.value
})
ElMessage.success('配置保存成功')
// 保存完成后重新拉取数据,避免本地状态与服务端策略偏差
// 保存完成后重新拉取数据,避免本地状态与服务端策略偏差
await loadPageData()
} finally {
loading.save = false
@@ -183,7 +201,7 @@ const handleRun = async () => {
jobSource: 'MANUAL'
})
ElMessage.success('监控任务已启动')
// 手动触发任务后刷新摘要,展示最新任务状态
// 手动触发任务后刷新摘要,展示最新任务状态
await loadPageData()
} finally {
loading.run = false

View File

@@ -52,3 +52,26 @@ export const validateTarget = (target: DiskMonitor.TargetItem, exists: string[])
if (target.alarmUsagePercent < target.warningUsagePercent) return '告警使用率不能小于预警使用率'
return ''
}
export const validateTargetNotifications = (target: DiskMonitor.TargetItem) => {
if (target.notifyPathEnabled) {
const hasInvalidPath = (target.notifyPathList || []).some(item => !item.path?.trim())
if (hasInvalidPath) return '路径通知目标路径不能为空'
}
if (target.notifyHttpEnabled) {
const hasInvalidUrl = (target.notifyHttpList || []).some(item => {
const url = item.url?.trim()
return !url || !/^https?:\/\/\S+$/i.test(url)
})
if (hasInvalidUrl) return 'HTTP 通知目标 URL 需要为有效的 HTTP/HTTPS 地址'
}
return ''
}
export const normalizeTargetItem = (target: DiskMonitor.TargetItem): DiskMonitor.TargetItem => ({
...target,
notifyPathList: Array.isArray(target.notifyPathList) ? target.notifyPathList : [],
notifyHttpList: Array.isArray(target.notifyHttpList) ? target.notifyHttpList : []
})