feat 异常警告
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user