|
|
@@ -5,7 +5,7 @@
|
|
|
<div class="page-head">
|
|
|
<div class="page-head-text">
|
|
|
<div class="page-title">设备运行实时监测</div>
|
|
|
- <div class="page-sub">实时掌握排水监测设备在线率、监测值与报警阈值,可直接派单或发布预警</div>
|
|
|
+ <div class="page-sub">实时掌握排水监测设备在线率与实际监测数据,可筛选报警设备并直接派单</div>
|
|
|
</div>
|
|
|
<el-button :icon="Refresh" :loading="loading" @click="refreshAll">刷新</el-button>
|
|
|
</div>
|
|
|
@@ -70,13 +70,15 @@
|
|
|
<el-input v-model="query.equipmentCode" placeholder="请输入" clearable class="filter-input"
|
|
|
@keyup.enter="handleQuery" />
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="运行状态">
|
|
|
- <el-select v-model="query.runStatus" placeholder="全部" clearable class="filter-input">
|
|
|
- <el-option label="在线" value="online" />
|
|
|
- <el-option label="离线" value="offline" />
|
|
|
- <el-option label="报警" value="alarm" />
|
|
|
+ <el-form-item label="在线状态">
|
|
|
+ <el-select v-model="query.onlineStatus" placeholder="全部" clearable class="filter-input">
|
|
|
+ <el-option label="在线" :value="1" />
|
|
|
+ <el-option label="离线" :value="0" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
+ <el-form-item label="报警">
|
|
|
+ <el-checkbox v-model="query.alarmOnly" @change="handleQuery" />
|
|
|
+ </el-form-item>
|
|
|
<template v-if="filterExpanded">
|
|
|
<el-form-item label="设备类型">
|
|
|
<el-select v-model="query.equipmentTypeId" placeholder="全部" clearable class="filter-input">
|
|
|
@@ -92,12 +94,6 @@
|
|
|
<el-input v-model="query.equipmentLocation" placeholder="请输入" clearable class="filter-input"
|
|
|
@keyup.enter="handleQuery" />
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="设备状态">
|
|
|
- <el-select v-model="query.currentStatus" placeholder="全部" clearable class="filter-input">
|
|
|
- <el-option v-for="item in currentStatusOptions" :key="item.value" :label="item.label"
|
|
|
- :value="item.value" />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
</template>
|
|
|
<el-form-item class="filter-actions">
|
|
|
<el-button type="primary" :icon="Search" @click="handleQuery">搜索</el-button>
|
|
|
@@ -170,42 +166,25 @@
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column v-if="isColumnVisible('alarmStatus')" label="报警状态" min-width="90" align="center">
|
|
|
- <template #default="{ row }">
|
|
|
- <el-tag :type="row.alarmStatus === 1 ? 'danger' : 'success'">
|
|
|
- {{ row.alarmStatus === 1 ? '报警' : '正常' }}
|
|
|
- </el-tag>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column v-if="isColumnVisible('currentStatus')" label="设备状态" min-width="90" align="center">
|
|
|
+ <el-table-column v-if="isColumnVisible('actualData')" label="实际数据" min-width="240" show-overflow-tooltip>
|
|
|
<template #default="{ row }">
|
|
|
- <el-tag :type="statusTagType(row.currentStatus)">{{ statusText(row.currentStatus) }}</el-tag>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column v-if="isColumnVisible('waterLevel')" label="实时液位(m)" min-width="110" align="center">
|
|
|
- <template #default="{ row }">
|
|
|
- <span v-if="waterLevelOf(row) !== null" class="metric-value">{{ waterLevelOf(row) }}</span>
|
|
|
+ <span v-if="latestMetricsText(row) !== '—'" :class="{ 'cell-alarm': hasAlarmInLatest(row) }">
|
|
|
+ {{ latestMetricsText(row) }}
|
|
|
+ </span>
|
|
|
<span v-else class="muted">—</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column v-if="isColumnVisible('threshold')" label="报警阈值" min-width="150" align="center">
|
|
|
+ <el-table-column v-if="isColumnVisible('lastComm')" label="最后通讯" min-width="170" align="center">
|
|
|
<template #default="{ row }">
|
|
|
- <span v-if="thresholdText(row.equipmentCode)" class="threshold-text">{{ thresholdText(row.equipmentCode) }}</span>
|
|
|
- <span v-else class="muted">未配置</span>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column v-if="isColumnVisible('collectTime')" label="采集时间" min-width="165" align="center">
|
|
|
- <template #default="{ row }">
|
|
|
- <span v-if="collectTimeOf(row)">{{ collectTimeOf(row) }}</span>
|
|
|
+ <span v-if="lastCommOf(row)">{{ lastCommOf(row) }}</span>
|
|
|
<span v-else class="muted">—</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="操作" width="190" align="center" fixed="right">
|
|
|
+ <el-table-column label="操作" width="150" align="center" fixed="right">
|
|
|
<template #default="{ row }">
|
|
|
<el-button link type="primary" @click="handleView(row)">详情</el-button>
|
|
|
<el-button link type="primary" @click="handleLocate(row)">定位</el-button>
|
|
|
<el-button link type="warning" @click="openRepairDialog(row)">派单</el-button>
|
|
|
- <el-button link type="danger" @click="openWarningDialog(row)">预警</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
@@ -232,22 +211,16 @@
|
|
|
</el-descriptions>
|
|
|
|
|
|
<div class="detail-section-title">实时监测</div>
|
|
|
- <el-descriptions :column="3" border size="small">
|
|
|
+ <el-descriptions :column="2" border size="small">
|
|
|
<el-descriptions-item label="在线状态">
|
|
|
<el-tag :type="detailRow.onlineStatus === 1 ? 'success' : 'info'">
|
|
|
{{ detailRow.onlineStatus === 1 ? '在线' : '离线' }}
|
|
|
</el-tag>
|
|
|
</el-descriptions-item>
|
|
|
- <el-descriptions-item label="报警状态">
|
|
|
- <el-tag :type="detailRow.alarmStatus === 1 ? 'danger' : 'success'">
|
|
|
- {{ detailRow.alarmStatus === 1 ? '报警' : '正常' }}
|
|
|
- </el-tag>
|
|
|
+ <el-descriptions-item label="最后通讯">{{ lastCommOf(detailRow) || '—' }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="实际数据" :span="2">
|
|
|
+ <span :class="{ 'cell-alarm': hasAlarmInLatest(detailRow) }">{{ latestMetricsText(detailRow) }}</span>
|
|
|
</el-descriptions-item>
|
|
|
- <el-descriptions-item label="设备状态">
|
|
|
- <el-tag :type="statusTagType(detailRow.currentStatus)">{{ statusText(detailRow.currentStatus) }}</el-tag>
|
|
|
- </el-descriptions-item>
|
|
|
- <el-descriptions-item label="实时液位(m)">{{ waterLevelOf(detailRow) ?? '—' }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="采集时间" :span="2">{{ collectTimeOf(detailRow) || '—' }}</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
|
|
|
<div class="detail-section-title">报警阈值</div>
|
|
|
@@ -437,10 +410,10 @@ import { saveAs } from 'file-saver'
|
|
|
import locationIcon from '@/assets/images/location.png'
|
|
|
import {
|
|
|
getEquipmentTypeList,
|
|
|
- getLatestWaterLevelByDevice,
|
|
|
publishWarning
|
|
|
} from '@/api/drainage'
|
|
|
import { listEquipment } from '@/api/pipeNetwork/pdeviceInform'
|
|
|
+import { getEquipmentProfile } from '@/api/pipeNetwork/perception'
|
|
|
import { pageWarningThresholds } from '@/api/warningThreshold'
|
|
|
import { listWarningTypes } from '@/api/warning/list'
|
|
|
import { addWorkOrder, dispatchWorkOrder, workOrderUsers } from '@/api/pipeNetwork/ops/workOrder'
|
|
|
@@ -451,17 +424,9 @@ import useUserStore from '@/store/modules/user'
|
|
|
const ROOT_TYPE_ID = 2
|
|
|
/** 统计与导出的一次性拉取上限,排水设备量小,够用即可 */
|
|
|
const FULL_FETCH_SIZE = 500
|
|
|
-const COLUMN_STORAGE_KEY = 'drainage-sbyx-columns'
|
|
|
+const COLUMN_STORAGE_KEY = 'drainage-sbyx-columns-v2'
|
|
|
|
|
|
// ==================== 字典 / 选项 ====================
|
|
|
-const currentStatusOptions = [
|
|
|
- { label: '在用', value: 1 },
|
|
|
- { label: '闲置', value: 2 },
|
|
|
- { label: '维修', value: 3 },
|
|
|
- { label: '报废', value: 4 },
|
|
|
- { label: '待入库', value: 5 }
|
|
|
-]
|
|
|
-
|
|
|
/** 所属片区,与 DistrictEnum、字典 drainage_district 同口径 */
|
|
|
const districtOptions = [
|
|
|
{ label: '城南', value: 0 },
|
|
|
@@ -488,16 +453,6 @@ const orderLevelOptions = [
|
|
|
{ label: '低', value: 2 }
|
|
|
]
|
|
|
|
|
|
-function statusText(val) {
|
|
|
- const hit = currentStatusOptions.find((item) => item.value === val)
|
|
|
- return hit ? hit.label : '-'
|
|
|
-}
|
|
|
-
|
|
|
-function statusTagType(val) {
|
|
|
- const map = { 1: 'success', 2: 'info', 3: 'warning', 4: 'danger', 5: '' }
|
|
|
- return map[val] || 'info'
|
|
|
-}
|
|
|
-
|
|
|
function districtLabel(val) {
|
|
|
if (val === null || val === undefined || val === '') return '-'
|
|
|
const hit = districtOptions.find((item) => String(item.value) === String(val))
|
|
|
@@ -509,11 +464,11 @@ function emptyQuery() {
|
|
|
return {
|
|
|
equipmentName: '',
|
|
|
equipmentCode: '',
|
|
|
- runStatus: '',
|
|
|
+ onlineStatus: '',
|
|
|
+ alarmOnly: false,
|
|
|
equipmentTypeId: '',
|
|
|
district: '',
|
|
|
equipmentLocation: '',
|
|
|
- currentStatus: '',
|
|
|
pageNum: 1,
|
|
|
pageSize: 10
|
|
|
}
|
|
|
@@ -523,14 +478,6 @@ const query = ref(emptyQuery())
|
|
|
const filterExpanded = ref(false)
|
|
|
const typeOptions = ref([])
|
|
|
|
|
|
-/** 运行状态下拉 → 后端 onlineStatus / alarmStatus 两个参数,二者互斥 */
|
|
|
-function resolveStatusParams() {
|
|
|
- if (query.value.runStatus === 'online') return { onlineStatus: 1 }
|
|
|
- if (query.value.runStatus === 'offline') return { onlineStatus: 0 }
|
|
|
- if (query.value.runStatus === 'alarm') return { alarmStatus: 1 }
|
|
|
- return {}
|
|
|
-}
|
|
|
-
|
|
|
function buildFilterParams() {
|
|
|
return {
|
|
|
rootTypeId: ROOT_TYPE_ID,
|
|
|
@@ -539,8 +486,9 @@ function buildFilterParams() {
|
|
|
equipmentTypeId: query.value.equipmentTypeId || undefined,
|
|
|
district: query.value.district === '' || query.value.district === null ? undefined : query.value.district,
|
|
|
equipmentLocation: query.value.equipmentLocation || undefined,
|
|
|
- currentStatus: query.value.currentStatus === '' ? undefined : query.value.currentStatus,
|
|
|
- ...resolveStatusParams()
|
|
|
+ onlineStatus: query.value.onlineStatus === '' ? undefined : query.value.onlineStatus,
|
|
|
+ // 报警勾选框与「感知设备管理」同一口径:勾选即只看报警设备
|
|
|
+ alarmStatus: query.value.alarmOnly ? 1 : undefined
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -561,6 +509,8 @@ async function loadDevices() {
|
|
|
const page = res?.data && Array.isArray(res.data.records) ? res.data : res
|
|
|
tableData.value = page?.records || page?.rows || []
|
|
|
total.value = page?.total || 0
|
|
|
+ // 实际数据与最后通讯取自设备档案,跟列表同一轮刷新,避免两批数据对不上
|
|
|
+ await loadProfilesFor(tableData.value, { force: true })
|
|
|
} catch (error) {
|
|
|
console.error('设备列表加载失败', error)
|
|
|
tableData.value = []
|
|
|
@@ -616,27 +566,97 @@ async function loadStats() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// ==================== 实时监测值 / 报警阈值 ====================
|
|
|
-/** deviceCode -> { value, time } */
|
|
|
-const waterLevelMap = ref({})
|
|
|
-/** deviceCode -> 阈值配置列表 */
|
|
|
+// ==================== 实际数据 / 最后通讯(口径同远程测控) ====================
|
|
|
+/** equipmentId -> 设备档案(含 lastCommTime 与 recordView 采集记录) */
|
|
|
+const profileMap = ref({})
|
|
|
+/** 单次并发拉取的档案数:导出会跨页补档案,避免一次性打满后端 */
|
|
|
+const PROFILE_CONCURRENCY = 6
|
|
|
+/** deviceCode -> 阈值配置列表(仅详情抽屉与预警弹窗预填使用) */
|
|
|
const thresholdMap = ref({})
|
|
|
|
|
|
-async function loadWaterLevels() {
|
|
|
- try {
|
|
|
- const res = await getLatestWaterLevelByDevice()
|
|
|
- const list = Array.isArray(res) ? res : (res?.data || [])
|
|
|
- const map = {}
|
|
|
- list.forEach((item) => {
|
|
|
- const code = item?.deviceCode
|
|
|
- if (!code) return
|
|
|
- map[code] = { value: item.waterLevel, time: item.createTime }
|
|
|
- })
|
|
|
- waterLevelMap.value = map
|
|
|
- } catch (error) {
|
|
|
- console.warn('液位实时数据加载失败', error)
|
|
|
- waterLevelMap.value = {}
|
|
|
+function profileOf(row) {
|
|
|
+ if (!row?.equipmentId) return null
|
|
|
+ return profileMap.value[row.equipmentId] || null
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 按设备档案补齐实时数据。已缓存的设备默认不再重复拉取,导出时可用 force 刷新。
|
|
|
+ */
|
|
|
+async function loadProfilesFor(rows, { force = false } = {}) {
|
|
|
+ const targets = (rows || []).filter(
|
|
|
+ (row) => row?.equipmentId && (force || !profileMap.value[row.equipmentId])
|
|
|
+ )
|
|
|
+ if (targets.length === 0) return
|
|
|
+ let cursor = 0
|
|
|
+ const worker = async () => {
|
|
|
+ while (cursor < targets.length) {
|
|
|
+ const row = targets[cursor]
|
|
|
+ cursor += 1
|
|
|
+ try {
|
|
|
+ const res = await getEquipmentProfile(row.equipmentId)
|
|
|
+ profileMap.value[row.equipmentId] = res?.data || null
|
|
|
+ } catch (error) {
|
|
|
+ console.warn('设备档案加载失败', row.equipmentId, error)
|
|
|
+ profileMap.value[row.equipmentId] = null
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+ await Promise.all(
|
|
|
+ Array.from({ length: Math.min(PROFILE_CONCURRENCY, targets.length) }, () => worker())
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+function latestRowOf(row) {
|
|
|
+ const rows = profileOf(row)?.recordView?.rows || []
|
|
|
+ return rows.length ? rows[0] : null
|
|
|
+}
|
|
|
+
|
|
|
+function columnLabelMap(profile) {
|
|
|
+ const map = {}
|
|
|
+ ;(profile?.recordView?.columns || []).forEach((col) => {
|
|
|
+ map[col.key] = col
|
|
|
+ })
|
|
|
+ return map
|
|
|
+}
|
|
|
+
|
|
|
+/** 实际数据:最新一条采集记录的指标拼成「指标:值+单位」,任一指标报警时整格标红 */
|
|
|
+function latestMetricsText(row) {
|
|
|
+ const first = latestRowOf(row)
|
|
|
+ if (!first) return '—'
|
|
|
+ const colMap = columnLabelMap(profileOf(row))
|
|
|
+ const text = (first.cells || [])
|
|
|
+ .filter((cell) => cell.key !== 'filepath')
|
|
|
+ .map((cell) => {
|
|
|
+ const col = colMap[cell.key]
|
|
|
+ const label = col?.label || cell.key
|
|
|
+ // value 为纯值,单位在列定义里;display 已含单位,仅在无有效纯值时兜底
|
|
|
+ const value = cell.value && cell.value !== '' && cell.value !== '—'
|
|
|
+ ? `${cell.value}${col?.unit || ''}`
|
|
|
+ : (cell.display || '—')
|
|
|
+ return `${label}:${value}`
|
|
|
+ })
|
|
|
+ .join(' ')
|
|
|
+ return text || '—'
|
|
|
+}
|
|
|
+
|
|
|
+function hasAlarmInLatest(row) {
|
|
|
+ const first = latestRowOf(row)
|
|
|
+ return (first?.cells || []).some((cell) => cell.alarm)
|
|
|
+}
|
|
|
+
|
|
|
+function lastCommOf(row) {
|
|
|
+ return profileOf(row)?.lastCommTime || ''
|
|
|
+}
|
|
|
+
|
|
|
+/** 预警弹窗「当前值」预填:取最新记录里第一个有效指标值 */
|
|
|
+function firstMetricValue(row) {
|
|
|
+ const first = latestRowOf(row)
|
|
|
+ const colMap = columnLabelMap(profileOf(row))
|
|
|
+ const cell = (first?.cells || []).find(
|
|
|
+ (item) => item.key !== 'filepath' && item.value && item.value !== '' && item.value !== '—'
|
|
|
+ )
|
|
|
+ if (!cell) return ''
|
|
|
+ return `${cell.value}${colMap[cell.key]?.unit || ''}`
|
|
|
}
|
|
|
|
|
|
async function loadThresholds() {
|
|
|
@@ -659,18 +679,6 @@ async function loadThresholds() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/** 液位值:空值返回 null,便于模板区分「没有数据」和「取了 0」 */
|
|
|
-function waterLevelOf(row) {
|
|
|
- const hit = row?.equipmentCode ? waterLevelMap.value[row.equipmentCode] : null
|
|
|
- if (!hit || hit.value === null || hit.value === undefined || hit.value === '') return null
|
|
|
- return hit.value
|
|
|
-}
|
|
|
-
|
|
|
-function collectTimeOf(row) {
|
|
|
- const hit = row?.equipmentCode ? waterLevelMap.value[row.equipmentCode] : null
|
|
|
- return hit?.time || ''
|
|
|
-}
|
|
|
-
|
|
|
/** 阈值文案:dataType 0 区间 / 1 仅下限 / 2 仅上限 */
|
|
|
function formatThreshold(item) {
|
|
|
if (!item) return '-'
|
|
|
@@ -683,13 +691,6 @@ function formatThreshold(item) {
|
|
|
return `${min ?? '-'} ~ ${max ?? '-'}${unit}`
|
|
|
}
|
|
|
|
|
|
-function thresholdText(code) {
|
|
|
- const list = thresholdMap.value[code]
|
|
|
- if (!list || list.length === 0) return ''
|
|
|
- const first = formatThreshold(list[0])
|
|
|
- return list.length > 1 ? `${first}(共 ${list.length} 项)` : first
|
|
|
-}
|
|
|
-
|
|
|
// ==================== 列设置 ====================
|
|
|
const columnDefs = [
|
|
|
{ key: 'equipmentName', label: '设备名称' },
|
|
|
@@ -698,11 +699,8 @@ const columnDefs = [
|
|
|
{ key: 'equipmentLocation', label: '安装位置' },
|
|
|
{ key: 'district', label: '所属片区' },
|
|
|
{ key: 'onlineStatus', label: '在线状态' },
|
|
|
- { key: 'alarmStatus', label: '报警状态' },
|
|
|
- { key: 'currentStatus', label: '设备状态' },
|
|
|
- { key: 'waterLevel', label: '实时液位' },
|
|
|
- { key: 'threshold', label: '报警阈值' },
|
|
|
- { key: 'collectTime', label: '采集时间' }
|
|
|
+ { key: 'actualData', label: '实际数据' },
|
|
|
+ { key: 'lastComm', label: '最后通讯' }
|
|
|
]
|
|
|
|
|
|
function defaultColumnKeys() {
|
|
|
@@ -1032,9 +1030,9 @@ function openWarningDialog(row) {
|
|
|
userIds: []
|
|
|
})
|
|
|
warningFormRef.value?.clearValidate()
|
|
|
- // 有实时液位就预填当前值,省一次手工输入
|
|
|
- const level = waterLevelOf(rows[0])
|
|
|
- if (level !== null) warningForm.currentValue = String(level)
|
|
|
+ // 有实时数据就预填当前值,省一次手工输入
|
|
|
+ const metric = firstMetricValue(rows[0])
|
|
|
+ if (metric) warningForm.currentValue = metric
|
|
|
const threshold = thresholdMap.value[rows[0]?.equipmentCode]?.[0]
|
|
|
if (threshold) warningForm.thresholdValue = formatThreshold(threshold)
|
|
|
warningVisible.value = true
|
|
|
@@ -1185,11 +1183,12 @@ const EXPORT_PAGE_SIZE = 100
|
|
|
|
|
|
const EXPORT_HEADER = [
|
|
|
'设备名称', '设备编码', '设备类型', '安装位置', '所属片区',
|
|
|
- '在线状态', '报警状态', '设备状态', '实时液位(m)', '报警阈值',
|
|
|
- '采集时间', '权属单位', '维护人员'
|
|
|
+ '在线状态', '实际数据', '最后通讯',
|
|
|
+ '权属单位', '维护人员'
|
|
|
]
|
|
|
|
|
|
function exportValues(row) {
|
|
|
+ const metrics = latestMetricsText(row)
|
|
|
return [
|
|
|
row.equipmentName || '',
|
|
|
row.equipmentCode || '',
|
|
|
@@ -1197,11 +1196,8 @@ function exportValues(row) {
|
|
|
row.equipmentLocation || '',
|
|
|
districtLabel(row.district),
|
|
|
row.onlineStatus === 1 ? '在线' : '离线',
|
|
|
- row.alarmStatus === 1 ? '报警' : '正常',
|
|
|
- statusText(row.currentStatus),
|
|
|
- waterLevelOf(row) ?? '',
|
|
|
- thresholdText(row.equipmentCode) || '未配置',
|
|
|
- collectTimeOf(row) || '',
|
|
|
+ metrics === '—' ? '' : metrics,
|
|
|
+ lastCommOf(row),
|
|
|
row.ownershipUnit || '',
|
|
|
row.maintainer || ''
|
|
|
]
|
|
|
@@ -1247,11 +1243,13 @@ async function handleExport() {
|
|
|
ElMessage.warning('当前条件下没有可导出的数据')
|
|
|
return
|
|
|
}
|
|
|
+ // 跨页导出时当前页之外的设备还没有档案,先补一次实际数据与最后通讯
|
|
|
+ await loadProfilesFor(rows)
|
|
|
const sheet = XLSX.utils.aoa_to_sheet([EXPORT_HEADER, ...rows.map(exportValues)])
|
|
|
sheet['!cols'] = [
|
|
|
{ wch: 22 }, { wch: 20 }, { wch: 20 }, { wch: 30 }, { wch: 10 },
|
|
|
- { wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 12 }, { wch: 18 },
|
|
|
- { wch: 20 }, { wch: 20 }, { wch: 12 }
|
|
|
+ { wch: 10 }, { wch: 40 }, { wch: 20 },
|
|
|
+ { wch: 20 }, { wch: 12 }
|
|
|
]
|
|
|
const book = XLSX.utils.book_new()
|
|
|
XLSX.utils.book_append_sheet(book, sheet, '设备运行实时监测')
|
|
|
@@ -1281,7 +1279,7 @@ async function loadTypeOptions() {
|
|
|
}
|
|
|
|
|
|
async function refreshAll() {
|
|
|
- await Promise.all([loadDevices(), loadStats(), loadWaterLevels(), loadThresholds()])
|
|
|
+ await Promise.all([loadDevices(), loadStats(), loadThresholds()])
|
|
|
}
|
|
|
|
|
|
onMounted(() => {
|
|
|
@@ -1469,14 +1467,9 @@ onMounted(() => {
|
|
|
font-weight: 400;
|
|
|
}
|
|
|
|
|
|
-.metric-value {
|
|
|
+.cell-alarm {
|
|
|
+ color: #ef4444;
|
|
|
font-weight: 600;
|
|
|
- color: #0a1628;
|
|
|
-}
|
|
|
-
|
|
|
-.threshold-text {
|
|
|
- color: #4e5969;
|
|
|
- font-size: 13px;
|
|
|
}
|
|
|
|
|
|
.column-setting-head {
|