feat 异常警告

This commit is contained in:
Ironsp
2026-09-14 15:10:48 +08:00
parent 3d857002e0
commit dd7c8b4162
9 changed files with 443 additions and 68 deletions

View File

@@ -1,4 +1,8 @@
<script setup lang="ts">
import type { WarningRecord } from '@/service/warningRecord'
import { onLoad } from '@dcloudio/uni-app'
import { ref } from 'vue'
import { warningRecordService } from '@/service'
import storage from '@/utils/storage'
definePage({
@@ -8,9 +12,30 @@ definePage({
},
})
const warningData = ref<any>(null)
/** 异常类型 / 级别 / 处置类型文案 */
const exceptionTypeMap: Record<number, string> = {
0: '数据中断',
1: '高温异常',
2: '定位异常',
}
const exceptionLevelMap: Record<number, string> = {
0: '提醒',
1: '警告',
2: '严重',
}
const disposalTypeMap: Record<number, string> = {
0: '未处理',
1: '现场恢复',
2: '需要保修',
}
onLoad((options) => {
const warningData = ref<WarningRecord | null>(null)
onLoad(async (options) => {
if (options?.id) {
warningData.value = await warningRecordService.selectById(Number(options.id))
return
}
if (options?.key) {
warningData.value = storage.get(options.key)
storage.remove(options.key)
@@ -23,10 +48,66 @@ onLoad((options) => {
<back-nav title="警告详情" />
<view class="content">
<view v-if="warningData" class="detail-raw">
<text class="raw-text">
{{ JSON.stringify(warningData, null, 2) }}
</text>
<view v-if="warningData" class="detail-card">
<view class="row">
<text class="label">
设备名称
</text>
<text class="value">
{{ warningData.device_name || '-' }}
</text>
</view>
<view class="row">
<text class="label">
异常类型
</text>
<text class="value">
{{ exceptionTypeMap[warningData.exception_type ?? -1] || '-' }}
</text>
</view>
<view class="row">
<text class="label">
异常级别
</text>
<text class="value">
{{ exceptionLevelMap[warningData.exception_level ?? -1] || '-' }}
</text>
</view>
<view class="row">
<text class="label">
发生时间
</text>
<text class="value">
{{ warningData.occurred_at || '-' }}
</text>
</view>
<view class="row">
<text class="label">
现场描述
</text>
<text class="value">
{{ warningData.site_description || '-' }}
</text>
</view>
<view class="row">
<text class="label">
处置类型
</text>
<text class="value">
{{ disposalTypeMap[warningData.disposal_type ?? -1] || '-' }}
</text>
</view>
<view class="row">
<text class="label">
处置记录
</text>
<text class="value">
{{ warningData.disposal_record || '-' }}
</text>
</view>
</view>
<view v-else class="empty-tip">
未找到告警详情
</view>
</view>
</view>
@@ -43,16 +124,38 @@ onLoad((options) => {
padding-top: 72px;
}
.detail-raw {
.detail-card {
background-color: #ffffff;
border-radius: 12px;
padding: 16px;
}
.raw-text {
font-size: 18px;
.row {
display: flex;
padding: 12px 0;
border-bottom: 1px solid #f5f5f5;
}
.row:last-child {
border-bottom: none;
}
.label {
width: 90px;
flex-shrink: 0;
font-size: 16px;
color: #999;
}
.value {
flex: 1;
font-size: 16px;
color: #333;
font-family: monospace;
white-space: pre-wrap;
}
.empty-tip {
text-align: center;
color: #999;
padding: 24px 0;
}
</style>

View File

@@ -1,4 +1,8 @@
<script setup lang="ts">
import type { WarningRecord } from '@/service/warningRecord'
import { computed, onMounted, ref } from 'vue'
import { useDbStore } from '@/store/modules/db'
definePage({
layout: false,
style: {
@@ -6,22 +10,107 @@ definePage({
},
})
const warnings = [
{
deviceName: '徐工XS65H #01',
tags: ['定位异常', '警告'],
time: '14:10:04·已持续5分30秒',
trigger: '触发阈值:RTK信号弱,精度下降',
status: '未处理' as const,
},
{
deviceName: '徐工XS65H #01',
tags: ['定位异常', '警告'],
time: '14:10:04·已持续5分30秒',
trigger: '触发阈值:RTK信号弱,精度下降',
status: '未处理' as const,
},
]
const db = useDbStore()
/** 异常类型:0 数据中断 / 1 高温异常 / 2 定位异常 */
const exceptionTypeMap: Record<number, string> = {
0: '数据中断',
1: '高温异常',
2: '定位异常',
}
/** 异常级别:0 提醒 / 1 警告 / 2 严重 */
const exceptionLevelMap: Record<number, string> = {
0: '提醒',
1: '警告',
2: '严重',
}
const activeTab = ref(0) // 0全部 1数据中断 2高温异常 3定位异常
const levelFilter = ref<number | null>(null) // null全部 / 0提醒 / 1警告 / 2严重
const dateRange = ref('') // ''全部 / today / yesterday / week / month
const totalCount = computed(() => db.warning_record.length)
const unhandledCount = computed(() =>
db.warning_record.filter(item => item.disposal_type === 0).length,
)
const warnings = computed(() => {
return db.warning_record
.filter((item) => {
if (activeTab.value > 0 && item.exception_type !== activeTab.value - 1)
return false
if (levelFilter.value !== null && item.exception_level !== levelFilter.value)
return false
if (dateRange.value && !matchDateRange(item.occurred_at, dateRange.value))
return false
return true
})
.map(mapWarningItem)
})
function parseDate(value?: string) {
if (!value)
return null
const date = new Date(value.replace(/-/g, '/'))
return Number.isNaN(date.getTime()) ? null : date
}
function startOfDay(date: Date) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate())
}
/** 按今天 / 昨天 / 本周 / 本月筛选发生时间 */
function matchDateRange(occurredAt: string | undefined, range: string) {
const occurred = parseDate(occurredAt)
if (!occurred)
return false
const now = new Date()
const todayStart = startOfDay(now)
const occurredStart = startOfDay(occurred)
if (range === 'today')
return occurredStart.getTime() === todayStart.getTime()
if (range === 'yesterday') {
const yesterday = new Date(todayStart)
yesterday.setDate(yesterday.getDate() - 1)
return occurredStart.getTime() === yesterday.getTime()
}
if (range === 'week') {
// 本周一 00:00 起
const weekStart = new Date(todayStart)
const day = weekStart.getDay() || 7 // 周日按 7
weekStart.setDate(weekStart.getDate() - day + 1)
return occurredStart.getTime() >= weekStart.getTime() && occurredStart.getTime() <= todayStart.getTime()
}
if (range === 'month') {
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1)
return occurredStart.getTime() >= monthStart.getTime() && occurredStart.getTime() <= todayStart.getTime()
}
return true
}
function mapWarningItem(item: WarningRecord) {
const typeText = exceptionTypeMap[item.exception_type ?? -1] || '未知异常'
const levelText = exceptionLevelMap[item.exception_level ?? -1] || ''
return {
id: item.id,
deviceName: item.device_name || '未知设备',
tags: [typeText, levelText].filter(Boolean),
time: item.occurred_at || '',
status: (item.disposal_type === 0 ? '未处理' : '已处理') as '未处理' | '已处理',
}
}
onMounted(async () => {
if (!db.warning_record.length)
await db.loadAll()
})
</script>
<template>
@@ -29,17 +118,26 @@ const warnings = [
<back-nav title="异常警告" />
<view class="content">
<warning-filter />
<warning-filter
v-model:active-tab="activeTab"
v-model:level="levelFilter"
v-model:date-range="dateRange"
:total-count="totalCount"
:unhandled-count="unhandledCount"
/>
<view class="warning-list">
<view v-if="!warnings.length" class="empty-tip">
暂无异常警告
</view>
<warning-item
v-for="(item, index) in warnings"
:key="index"
:key="item.id ?? index"
:index="index"
:warning-id="item.id"
:device-name="item.deviceName"
:tags="item.tags"
:time="item.time"
:trigger="item.trigger"
:status="item.status"
/>
</view>
@@ -63,4 +161,11 @@ const warnings = [
flex-direction: column;
gap: 12px;
}
.empty-tip {
font-size: 14px;
color: #999;
text-align: center;
padding: 24px 0;
}
</style>