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