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 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
|
||||
|
||||
@@ -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 : []
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user