feat(udp): 实现UDP通信历史记录存储与管理功能(后续测试完成之后需要恢复TelegramDispatcher,UdpSender,UdpServer,TelegramSchema这几个不然投入生产会导致OOM)

- 修改application.yml中的远程端口配置从9000调整为9001
- 在TelegramDispatcher中注入TelegramStore并实现报文存储功能
- 新增TelegramRecord类用于定义报文记录的数据结构
- 创建TelegramStore组件用于管理UDP报文的历史记录
- 更新前端udp-debug.vue界面的字段映射和数据展示逻辑
- 实现后端API接口支持历史记录查询、统计和清空操作
- 优化UDP接收日志输出并增加数据预览功能
- 重构前端API调用参数以支持分页查询功能
This commit is contained in:
2026-05-05 14:43:38 +08:00
parent 2e17943a7e
commit 4fea237b33
11 changed files with 384 additions and 191 deletions

View File

@@ -1,6 +1,5 @@
import request from '@/utils/request'
// UDP 服务器配置
export function getUdpConfig() {
return request({ url: '/mill/udp/config', method: 'get' })
}
@@ -9,7 +8,6 @@ export function updateUdpConfig(data) {
return request({ url: '/mill/udp/config', method: 'put', data })
}
// 发送 UDP 报文
export function sendTelegram(data) {
return request({
url: '/mill/udp/send',
@@ -18,7 +16,6 @@ export function sendTelegram(data) {
})
}
// 获取电文历史记录
export function getTelegramHistory(query) {
return request({
url: '/mill/udp/history',
@@ -27,16 +24,18 @@ export function getTelegramHistory(query) {
})
}
// 获取当前电文统计
export function getTelegramStats() {
return request({ url: '/mill/udp/stats', method: 'get' })
}
// 解析电文数据
export function parseTelegram(tcNo, payload) {
return request({
url: '/mill/udp/parse',
method: 'post',
data: { tcNo, payload }
})
}
export function clearTelegramHistory() {
return request({ url: '/mill/udp/history', method: 'delete' })
}

View File

@@ -20,12 +20,12 @@
</el-col>
<el-col :span="8">
<el-form-item label="目标端口">
<el-input-number v-model="configForm.targetPort" :min="1024" :max="65535" />
<el-input-number v-model="configForm.remotePort" :min="1024" :max="65535" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="目标IP">
<el-input v-model="configForm.targetIp" placeholder="192.168.1.100" />
<el-input v-model="configForm.remoteHost" placeholder="192.168.1.100" />
</el-form-item>
</el-col>
</el-row>
@@ -184,7 +184,7 @@
height="400"
style="margin-top: 10px;"
>
<el-table-column prop="id" label="#" width="40" align="center" />
<el-table-column prop="id" label="#" align="center" />
<el-table-column prop="tcNo" label="电文号" width="80" align="center" />
<el-table-column prop="direction" label="方向" width="60" align="center">
<template slot-scope="{ row }">
@@ -254,7 +254,8 @@ import {
sendTelegram,
getTelegramHistory,
getTelegramStats,
parseTelegram
parseTelegram,
clearTelegramHistory
} from '@/api/mill/udp'
export default {
@@ -267,8 +268,8 @@ export default {
// 配置表单
configForm: {
localPort: 8080,
targetPort: 8081,
targetIp: '192.168.1.100',
remotePort: 8081,
remoteHost: '192.168.1.100',
bufferSize: 8192,
timeout: 5000,
retryCount: 3
@@ -487,17 +488,26 @@ export default {
this.sending = true
try {
let payload
let tcNo = this.selectedTcNo
let requestData
if (this.activeTab === 'json') {
payload = Buffer.from(JSON.stringify(this.telegramData.json), 'utf8')
let parsedData
try {
parsedData = JSON.parse(this.telegramData.json)
} catch (e) {
this.$message.error('JSON格式错误: ' + e.message)
return
}
requestData = { tcNo, data: parsedData }
} else if (this.activeTab === 'hex') {
// 转换十六进制字符串为字节数组
const hexStr = this.telegramData.hex.replace(/\s/g, '')
payload = Buffer.from(hexStr, 'hex')
const bytes = []
for (let i = 0; i < hexStr.length; i += 2) {
bytes.push(parseInt(hexStr.substr(i, 2), 16))
}
requestData = { tcNo, payload: bytes }
} else if (this.activeTab === 'form') {
// 根据电文号构造数据
const fields = this.getFieldsForTcNo(this.selectedTcNo)
const formData = {}
@@ -516,24 +526,13 @@ export default {
}
}
})
payload = Buffer.from(JSON.stringify(formData), 'utf8')
requestData = { tcNo, data: formData }
}
const response = await sendTelegram({ tcNo, payload: Array.from(payload) })
const response = await sendTelegram(requestData)
this.$message.success(`报文 ${tcNo} 发送成功`)
// 添加到历史记录
this.historyList.unshift({
id: Date.now(),
tcNo,
direction: 'OUT',
timestamp: new Date().toLocaleString(),
payloadLength: payload.length,
status: '成功'
})
this.loadHistory()
this.loadStats()
} catch (error) {
@@ -545,7 +544,11 @@ export default {
// 查看详情
viewDetail(record) {
this.currentDetail = record
this.currentDetail = {
...record,
rawPayload: record.rawPayload || '无原始数据',
parsedFields: record.parsedFields || []
}
this.detailDialogVisible = true
},
@@ -570,20 +573,25 @@ export default {
this.$confirm('确定要清空所有历史记录吗?', '提示', {
type: 'warning'
}).then(() => {
this.historyList = []
this.stats = {
todayReceived: 0,
totalReceived: 0,
successRate: 0,
avgDelay: 0
}
clearTelegramHistory().then(() => {
this.historyList = []
this.stats = {
todayReceived: 0,
totalReceived: 0,
successRate: 0,
avgDelay: 0
}
this.$message.success('历史记录已清空')
}).catch(() => {
this.$message.error('清空失败')
})
})
},
// 加载历史记录
loadHistory() {
getTelegramHistory({ page: 1, size: 50 }).then(res => {
this.historyList = res.rows || []
getTelegramHistory({ pageNum: 1, pageSize: 50 }).then(res => {
this.historyList = (res.data && res.data.rows) || []
}).catch(() => {
this.$message.error('加载历史记录失败')
})
@@ -592,14 +600,13 @@ export default {
// 加载统计数据
loadStats() {
getTelegramStats().then(res => {
this.stats = res.data || this.stats
this.stats = (res.data && res.data) || this.stats
}).catch(() => {
// 使用本地计算
this.stats = {
todayReceived: this.historyList.filter(h => h.direction === 'IN').length,
totalReceived: this.historyList.length,
successRate: this.historyList.length > 0 ? Math.round((this.historyList.filter(h => h.status === '成功').length / this.historyList.length) * 100) : 0,
avgDelay: 150
avgDelay: 0
}
})
},
@@ -700,4 +707,4 @@ export default {
}
}
}
</style>
</style>