feat(import): 添加区域字段支持和改进模板路径处理

- 在OLT设备导入功能中添加region字段支持,从Excel模板读取区域信息
- 修复模板文件路径问题,使用相对路径动态构建模板文件路径
- 更新导入服务中的验证错误格式,包含行号和MAC地址信息

feat(check): 增强设备检测服务的端口信息同步

- 在CheckService中添加端口和OLT归属信息的同步逻辑
- 改进设备状态检查时的端口信息更新策略,避免用None覆盖现有值
- 扩展返回数据结构,包含端口ID、槽位号、端口号和OLT位置信息

feat(frontend): 添加设备列表刷新冷却机制和端口验证

- 实现设备状态刷新的60秒冷却时间限制,防止频繁操作
- 改进业务下发按钮的启用条件,同时支持port_id或slot_number+port_number组合
- 优化导入结果显示,显示具体的MAC地址信息

feat(olt): 添加重复MAC记录批量清除功能

- 新增批量清除重复MAC记录的功能,支持按OLT分组处理
- 实现SSH端口清除和自动忽略的批量操作流程
- 添加批量操作的进度提示和错误处理机制
```
This commit is contained in:
2026-04-09 11:33:04 +08:00
parent dcb2435514
commit d222978ae4
9 changed files with 1016 additions and 15 deletions
+52
View File
@@ -454,6 +454,7 @@
</el-table-column>
</el-table>
<template #footer>
<el-button v-if="can('olt.manage') && dupList.length > 0" type="danger" :loading="batchClearing" @click="batchClearAll">批量清除并忽略</el-button>
<el-button @click="dupVisible = false">关闭</el-button>
</template>
</el-dialog>
@@ -533,6 +534,7 @@ const scanResult = ref({ total: 0, new: 0, devices: [], duplicates: [] })
const dupList = ref([])
const duplicateCount = ref(0)
const clearingPort = ref('')
const batchClearing = ref(false)
const newDevList = ref([])
const newDeviceCount = ref(0)
const newDevVisible = ref(false)
@@ -766,6 +768,56 @@ const deleteDupRecord = async (id) => {
}
}
const batchClearAll = async () => {
const total = dupList.value.length
if (total === 0) return
try {
await ElMessageBox.confirm(
`将对 ${total} 条重复 MAC 记录的所有离线端口执行 SSH 清除,然后自动忽略全部记录。此操作不可撤销,确认继续?`,
'批量清除确认',
{ type: 'warning', confirmButtonText: '确认清除', confirmButtonClass: 'el-button--danger' }
)
} catch {
return
}
batchClearing.value = true
// 按 olt_id 分组
const groups = {}
for (const row of dupList.value) {
const key = row.olt_id ?? '__unknown__'
if (!groups[key]) groups[key] = []
groups[key].push(row)
}
let cleared = 0, failed = 0
// 每个 OLT 一个并发任务,组内串行处理完所有重复 MAC 再结束
await Promise.all(
Object.values(groups).map(async (rows) => {
for (const row of rows) {
const offlinePorts = (row.ports || []).filter(p => p.status !== 'online')
for (const p of offlinePorts) {
try {
await request.post(`/olt/duplicate-macs/${row.id}/clear-port`, { port_id: p.port_id })
cleared++
} catch {
failed++
}
}
try {
await request.delete(`/olt/duplicate-macs/${row.id}`)
} catch {}
}
})
)
dupList.value = []
duplicateCount.value = 0
batchClearing.value = false
ElMessage.success(`批量清除完成:清除 ${cleared} 个端口${failed ? `${failed} 个失败` : ''},已忽略全部 ${total} 条记录`)
}
const fetchNewDeviceCount = async () => {
try {
const { data } = await request.get('/olt/new-devices')