更改了事件报告的查询界面

This commit is contained in:
root 2026-06-26 18:06:50 +08:00
parent 00fe92c90e
commit 703f1730b8
8 changed files with 190 additions and 99 deletions

View File

@ -2,6 +2,7 @@ import { http } from './http'
import type { import type {
AiAlarmSettingItem, AiAlarmSettingItem,
AlarmEvent, AlarmEvent,
AlarmHistoryQuery,
ApiResponse, ApiResponse,
ChannelConfigPayload, ChannelConfigPayload,
DeviceConfigPayload, DeviceConfigPayload,
@ -53,8 +54,8 @@ export async function fetchSystemConfig(): Promise<SystemConfigPayload> {
return response.data.data return response.data.data
} }
export async function fetchAlarmHistory(pageOrParams: number | any = 1, size = 20): Promise<AlarmEvent[]> { export async function fetchAlarmHistory(pageOrParams: number | AlarmHistoryQuery = 1, size = 20): Promise<AlarmEvent[]> {
let params: any let params: AlarmHistoryQuery
if (typeof pageOrParams === 'number') { if (typeof pageOrParams === 'number') {
params = { page: pageOrParams, size } params = { page: pageOrParams, size }
} else { } else {
@ -128,4 +129,4 @@ export async function saveSystemConfig(payload: SystemConfigPayload): Promise<Ap
export async function saveDevicePassword(payload: { password: string }): Promise<ApiResponse<{ send_status: string }>> { export async function saveDevicePassword(payload: { password: string }): Promise<ApiResponse<{ send_status: string }>> {
const response = await http.post<ApiResponse<{ send_status: string }>>('/config/device/password', payload) const response = await http.post<ApiResponse<{ send_status: string }>>('/config/device/password', payload)
return response.data return response.data
} }

View File

@ -49,12 +49,21 @@ export interface DeviceStatus {
export interface AlarmEvent { export interface AlarmEvent {
id?: number id?: number
alarm_type: string event_time: string
time: string line_code: number
no: string event_type: number
type: string event_code: number
event_value: number
content: string content: string
level: string }
export interface AlarmHistoryQuery {
page?: number
size?: number
line_code?: number
event_type?: number
start_time?: string
end_time?: string
} }
export interface ApiResponse<T> { export interface ApiResponse<T> {

View File

@ -0,0 +1,73 @@
export function getAlarmBelongText(lineCode: number): string {
if (lineCode === 0) {
return '装置'
}
return `线路${lineCode}`
}
export function getEventTypeName(eventType: number): string {
switch (eventType) {
case 1:
return '保护类'
case 2:
return '动作类'
case 3:
return '报警类'
case 4:
return '操作类'
case 5:
return 'AI越限类'
default:
return `未知类型(${eventType})`
}
}
export function getEventCodeName(eventType: number, eventCode: number): string {
if (eventType === 1) {
if (eventCode === 1) {
return 'PT断线'
}
if (eventCode === 2) {
return 'CT断线'
}
return `保护事件${eventCode}`
}
if (eventType === 2) {
return `${eventCode}路状态变化`
}
if (eventType === 3) {
if (eventCode === 1) {
return '过压'
}
if (eventCode === 2) {
return '过流'
}
if (eventCode === 3) {
return '频率越限'
}
return `报警事件${eventCode}`
}
if (eventType === 4) {
return eventCode > 0 ? `界面操作${eventCode}` : '界面操作'
}
if (eventType === 5) {
return `AI通道${eventCode}越限`
}
return `未定义代码(${eventCode})`
}
export function getEventDisplayName(eventType: number, eventCode: number): string {
return `${getEventTypeName(eventType)} / ${getEventCodeName(eventType, eventCode)}`
}
export function formatAlarmEventValue(eventType: number, eventValue: number): string {
if (eventType === 2) {
return eventValue === 0 ? '分' : '合'
}
return String(eventValue)
}

View File

@ -2,6 +2,7 @@
import { computed, onMounted, ref } from 'vue' import { computed, onMounted, ref } from 'vue'
import { usePlatformStore } from '../../stores/platform' import { usePlatformStore } from '../../stores/platform'
import {fetchChannelConfig} from '@/api/platform' import {fetchChannelConfig} from '@/api/platform'
import { formatAlarmEventValue, getAlarmBelongText, getEventDisplayName } from '@/utils/alarmEvent'
const { state, bootstrap } = usePlatformStore() const { state, bootstrap } = usePlatformStore()
const channelConfig = ref<Record<number, { type: string; limit_low: number; limit_high: number; line_no: string }>>({}) const channelConfig = ref<Record<number, { type: string; limit_low: number; limit_high: number; line_no: string }>>({})
@ -33,24 +34,20 @@ function formatTime(dateStr: string): string {
const seconds = String(date.getSeconds()).padStart(2, '0') const seconds = String(date.getSeconds()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
} }
const tableData = computed(() => { const tableData = computed(() => {
const alarms = state.alarms || [] const alarms = state.alarms || []
const firstThree = alarms.slice(0, 1) const firstThree = alarms.slice(0, 1)
return firstThree.map(list => { return firstThree.map(list => {
const reslist: any = {} return {
if (list.alarm_type == 'line_alarm') { id: list.id || 0,
reslist.name = `线路${list?.no || 1}` name: getAlarmBelongText(list.line_code),
} else if (list.alarm_type == 'ai_alarm') { typeName: getEventDisplayName(list.event_type, list.event_code),
reslist.name = `通道${list?.no || 1}` eventCode: list.event_code,
} else if (list.alarm_type == 'operate_alarm') { eventValue: formatAlarmEventValue(list.event_type, list.event_value),
reslist.name = '' content: list.content,
time: list.event_time ? formatTime(list.event_time) : '',
} }
reslist.typeName = list.type
reslist.content = list.content
reslist.time = list.time ? formatTime(list.time) : ''
reslist.level = list.level || ''
reslist.id = list.id || '0'
return reslist
}) })
}) })
function init(){ function init(){
@ -108,7 +105,7 @@ onMounted(() => {
<div style="width: 8%;text-align: center;">{{ index + 1 }}</div> <div style="width: 8%;text-align: center;">{{ index + 1 }}</div>
<div style="width: 14%;text-align: center;">{{ item.name }}</div> <div style="width: 14%;text-align: center;">{{ item.name }}</div>
<div style="width: 20%;text-align: center;">{{ item.typeName }}</div> <div style="width: 20%;text-align: center;">{{ item.typeName }}</div>
<div style="width: 8%;text-align: center;">{{ item.level }}</div> <div style="width: 8%;text-align: center;">{{ item.eventValue }}</div>
<div style="width: 30%;text-align: center;">{{ item.content }}</div> <div style="width: 30%;text-align: center;">{{ item.content }}</div>
<div style="width: 20%;text-align: center;">{{ item.time }}</div> <div style="width: 20%;text-align: center;">{{ item.time }}</div>
</div> </div>
@ -216,4 +213,4 @@ onMounted(() => {
} }
} }
} }
</style> </style>

View File

@ -2,6 +2,7 @@
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { usePlatformStore } from '../../stores/platform' import { usePlatformStore } from '../../stores/platform'
import type { ValueGroup } from '../../types/platform' import type { ValueGroup } from '../../types/platform'
import { formatAlarmEventValue, getAlarmBelongText, getEventDisplayName } from '@/utils/alarmEvent'
const { state, bootstrap } = usePlatformStore() const { state, bootstrap } = usePlatformStore()
const lineList = ref([ const lineList = ref([
@ -121,20 +122,15 @@ const tableData = computed(() => {
const alarms = state.alarms || [] const alarms = state.alarms || []
const firstThree = alarms.slice(0, 1) const firstThree = alarms.slice(0, 1)
return firstThree.map(list => { return firstThree.map(list => {
const reslist: any = {} return {
if (list.alarm_type == 'line_alarm') { id: list.id || 0,
reslist.name = `线路${list?.no || 1}` name: getAlarmBelongText(list.line_code),
} else if (list.alarm_type == 'ai_alarm') { typeName: getEventDisplayName(list.event_type, list.event_code),
reslist.name = `通道${list?.no || 1}` eventCode: list.event_code,
} else if (list.alarm_type == 'operate_alarm') { eventValue: formatAlarmEventValue(list.event_type, list.event_value),
reslist.name = '' content: list.content,
time: list.event_time ? formatTime(list.event_time) : '',
} }
reslist.typeName = list.type
reslist.content = list.content
reslist.time = list.time ? formatTime(list.time) : ''
reslist.level = list.level || ''
reslist.id = list.id || '0'
return reslist
}) })
}) })
@ -218,7 +214,7 @@ onMounted(() => {
<div style="width: 8%;text-align: center;">{{ index + 1 }}</div> <div style="width: 8%;text-align: center;">{{ index + 1 }}</div>
<div style="width: 14%;text-align: center;">{{ item.name }}</div> <div style="width: 14%;text-align: center;">{{ item.name }}</div>
<div style="width: 20%;text-align: center;">{{ item.typeName }}</div> <div style="width: 20%;text-align: center;">{{ item.typeName }}</div>
<div style="width: 8%;text-align: center;">{{ item.level }}</div> <div style="width: 8%;text-align: center;">{{ item.eventValue }}</div>
<div style="width: 30%;text-align: center;">{{ item.content }}</div> <div style="width: 30%;text-align: center;">{{ item.content }}</div>
<div style="width: 20%;text-align: center;">{{ item.time }}</div> <div style="width: 20%;text-align: center;">{{ item.time }}</div>
</div> </div>

View File

@ -1,35 +1,65 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { fetchAlarmHistory } from '@/api/platform' import { fetchAlarmHistory } from '@/api/platform'
const formData: any = ref({ import type { AlarmEvent, AlarmHistoryQuery } from '@/types/platform'
no: null, import { formatAlarmEventValue, getAlarmBelongText, getEventCodeName, getEventTypeName } from '@/utils/alarmEvent'
type: '',
type AlarmRow = AlarmEvent & {
belong_text: string
event_type_text: string
event_code_text: string
event_value_text: string
}
const formData = ref<{
line_code: number | null
event_type: number | null
timeRange: string[]
}>({
line_code: null,
event_type: null,
timeRange: [], timeRange: [],
}) })
const tableData: any = ref([]) const tableData = ref<AlarmRow[]>([])
tableData.value = []
const pagination = ref({ const pagination = ref({
currentPage: 1, currentPage: 1,
pageSize: 10, pageSize: 10,
total: 0, total: 0,
}) })
const handleQuery = () => { const loadAlarms = () => {
const params: any = { const params: AlarmHistoryQuery = {
page: pagination.value.currentPage, page: pagination.value.currentPage,
size: pagination.value.pageSize, size: pagination.value.pageSize,
type: formData.value.type, }
if (formData.value.line_code !== null) {
params.line_code = formData.value.line_code
}
if (formData.value.event_type !== null) {
params.event_type = formData.value.event_type
} }
if (formData.value.timeRange && formData.value.timeRange.length > 0) { if (formData.value.timeRange && formData.value.timeRange.length > 0) {
params.start_time = formData.value.timeRange[0] params.start_time = formData.value.timeRange[0]
params.end_time = formData.value.timeRange[1] params.end_time = formData.value.timeRange[1]
} }
fetchAlarmHistory(params).then((res: any) => { fetchAlarmHistory(params).then((res) => {
tableData.value = res tableData.value = res.map((item) => ({
...item,
belong_text: getAlarmBelongText(item.line_code),
event_type_text: getEventTypeName(item.event_type),
event_code_text: getEventCodeName(item.event_type, item.event_code),
event_value_text: formatAlarmEventValue(item.event_type, item.event_value),
}))
pagination.value.total = tableData.value.length
}) })
} }
const handleQuery = () => {
pagination.value.currentPage = 1
loadAlarms()
}
const handleSizeChange = (val: number) => { const handleSizeChange = (val: number) => {
pagination.value.pageSize = val pagination.value.pageSize = val
pagination.value.currentPage = 1 pagination.value.currentPage = 1
@ -38,21 +68,9 @@ const handleSizeChange = (val: number) => {
const handleCurrentChange = (val: number) => { const handleCurrentChange = (val: number) => {
pagination.value.currentPage = val pagination.value.currentPage = val
handleQuery() loadAlarms()
}
function init() {
const params: any = {
page: pagination.value.currentPage,
size: pagination.value.pageSize,
}
if (formData.value.timeRange && formData.value.timeRange.length > 0) {
params.start_time = formData.value.timeRange[0]
params.end_time = formData.value.timeRange[1]
}
fetchAlarmHistory(params).then((res: any) => {
tableData.value = res
})
} }
const formatDate = (date: Date): string => { const formatDate = (date: Date): string => {
const pad = (n: number): string => n.toString().padStart(2, '0') const pad = (n: number): string => n.toString().padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}` return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
@ -66,25 +84,18 @@ const getDefaultTimeRange = (): [string, string] => {
} }
onMounted(() => { onMounted(() => {
formData.value.no = null formData.value.line_code = null
formData.value.type = '' formData.value.event_type = null
formData.value.timeRange = getDefaultTimeRange() formData.value.timeRange = getDefaultTimeRange()
init() loadAlarms()
}) })
</script> </script>
<template> <template>
<div class="event-report-container"> <div class="event-report-container">
<div class="search-box"> <div class="search-box">
<!-- <el-select v-model="formData.no" placeholder="所属线路" style="width: 180px"> <el-input-number v-model="formData.line_code" :min="0" :step="1" placeholder="请输入线路号" style="width: 180px" />
<el-option label="线路一" value="线路一" /> <el-input-number v-model="formData.event_type" :min="0" :step="1" placeholder="请输入事件类型" style="width: 180px; margin-left: 15px" />
<el-option label="线路二" value="线路二" />
</el-select> -->
<!-- <el-select v-model="formData.type" placeholder="事件类型" style="width: 180px; margin-left: 15px">
<el-option label="操作事件" value="操作事件" />
<el-option label="报警事件" value="报警事件" />
</el-select> -->
<el-input v-model="formData.type" placeholder="请输入事件类型" style="width: 180px" />
<div> <div>
<el-date-picker v-model="formData.timeRange" type="datetimerange" start-placeholder="开始时间" <el-date-picker v-model="formData.timeRange" type="datetimerange" start-placeholder="开始时间"
end-placeholder="结束时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" end-placeholder="结束时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
@ -98,17 +109,12 @@ onMounted(() => {
<el-table :data="tableData" style="width: 100%; height: calc(100vh - 260px)" header-align="center" <el-table :data="tableData" style="width: 100%; height: calc(100vh - 260px)" header-align="center"
align="center"> align="center">
<el-table-column label="序号" type="index" width="80" align="center" /> <el-table-column label="序号" type="index" width="80" align="center" />
<el-table-column label="事件所属" prop="belong"> <el-table-column label="事件所属" prop="belong_text" align="center" />
<template #default="scope"> <el-table-column label="事件类型" prop="event_type_text" align="center" />
<span v-if="scope.row.alarm_type === 'line_alarm'">线路{{ scope.row.no }}</span> <el-table-column label="事件代码" prop="event_code_text" align="center" min-width="140px" />
<span v-else-if="scope.row.alarm_type === 'ai_alarm'">通道{{ scope.row.no }}</span> <el-table-column label="动作值" prop="event_value_text" align="center" />
<span v-else-if="scope.row.alarm_type === 'operate_alarm'">{{ scope.row.no }}</span>
</template>
</el-table-column>
<el-table-column label="事件类型" prop="type" align="center" />
<el-table-column label="事件等级" prop="level" width="80" align="center" />
<el-table-column label="事件详情" prop="content" min-width="120px" align="center" /> <el-table-column label="事件详情" prop="content" min-width="120px" align="center" />
<el-table-column label="发生时间" prop="time" min-width="100px" align="center" /> <el-table-column label="发生时间" prop="event_time" min-width="160px" align="center" />
</el-table> </el-table>
<div class="pagination"> <div class="pagination">
<el-pagination v-model:current-page="pagination.currentPage" v-model:page-size="pagination.pageSize" <el-pagination v-model:current-page="pagination.currentPage" v-model:page-size="pagination.pageSize"
@ -196,4 +202,4 @@ onMounted(() => {
:deep(.el-range-editor.el-input__wrapper) { :deep(.el-range-editor.el-input__wrapper) {
min-height: 40px; min-height: 40px;
} }
</style> </style>

View File

@ -3,6 +3,7 @@ import { computed, onMounted } from 'vue'
import { usePlatformStore } from '../../stores/platform' import { usePlatformStore } from '../../stores/platform'
import {ElMessageBox, ElMessage} from 'element-plus' import {ElMessageBox, ElMessage} from 'element-plus'
import { controlSwitch } from '@/api/platform' import { controlSwitch } from '@/api/platform'
import { formatAlarmEventValue, getAlarmBelongText, getEventDisplayName } from '@/utils/alarmEvent'
const { state, bootstrap } = usePlatformStore() const { state, bootstrap } = usePlatformStore()
@ -35,24 +36,20 @@ function formatTime(dateStr: string): string {
const seconds = String(date.getSeconds()).padStart(2, '0') const seconds = String(date.getSeconds()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
} }
const tableData = computed(() => { const tableData = computed(() => {
const alarms = state.alarms || [] const alarms = state.alarms || []
const firstThree = alarms.slice(0, 1) const firstThree = alarms.slice(0, 1)
return firstThree.map(list => { return firstThree.map(list => {
const reslist: any = {} return {
if (list.alarm_type == 'line_alarm') { id: list.id || 0,
reslist.name = `线路${list?.no || 1}` name: getAlarmBelongText(list.line_code),
} else if (list.alarm_type == 'ai_alarm') { typeName: getEventDisplayName(list.event_type, list.event_code),
reslist.name = `通道${list?.no || 1}` eventCode: list.event_code,
} else if (list.alarm_type == 'operate_alarm') { eventValue: formatAlarmEventValue(list.event_type, list.event_value),
reslist.name = '' content: list.content,
time: list.event_time ? formatTime(list.event_time) : '',
} }
reslist.typeName = list.type
reslist.content = list.content
reslist.time = list.time ? formatTime(list.time) : ''
reslist.level = list.level || ''
reslist.id = list.id || '0'
return reslist
}) })
}) })
function outputChange(item:any,index:any){ function outputChange(item:any,index:any){
@ -233,4 +230,4 @@ onMounted(() => {
} }
} }
} }
</style> </style>

View File

@ -1,5 +1,9 @@
import type { AlarmEvent, RealtimeData } from '../types/platform' import type { AlarmEvent, RealtimeData } from '../types/platform'
type TimeSyncPayload = {
time_sync: string
}
function buildWsUrl(path: string): string { function buildWsUrl(path: string): string {
return `ws://localhost:8000${path}` return `ws://localhost:8000${path}`
} }
@ -35,3 +39,11 @@ export function connectAlarm(onMessage: (data: AlarmEvent) => void): WebSocket {
} }
return socket return socket
} }
export function connectTimeSync(onMessage: (data: { data: TimeSyncPayload }) => void): WebSocket {
const socket = new WebSocket(buildWsUrl('/ws/time-sync'))
socket.onmessage = (event) => {
onMessage(JSON.parse(event.data))
}
return socket
}