|
|
|
|
@ -1,4 +1,17 @@
|
|
|
|
|
<template>
|
|
|
|
|
<ContentWrap>
|
|
|
|
|
<div class="device-statistics">
|
|
|
|
|
<div
|
|
|
|
|
v-for="item in deviceStatisticsItems"
|
|
|
|
|
:key="item.key"
|
|
|
|
|
class="device-statistics__item"
|
|
|
|
|
:class="`device-statistics__item--${item.key}`"
|
|
|
|
|
>
|
|
|
|
|
<span class="device-statistics__label">{{ item.label }}</span>
|
|
|
|
|
<span class="device-statistics__value">{{ item.value }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</ContentWrap>
|
|
|
|
|
<ContentWrap>
|
|
|
|
|
<!-- 搜索工作栏 -->
|
|
|
|
|
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" min-label-width="68px">
|
|
|
|
|
@ -214,9 +227,9 @@
|
|
|
|
|
<!-- <i>📊</i>-->
|
|
|
|
|
<el-image
|
|
|
|
|
style="width: 60px; height: 60px"
|
|
|
|
|
:src="item.images || 'https://p119-minio-upload.ngsk.tech:7001/besure/998a6fc5d7da4ad079cc5afaa1ca5293917c17080c9805dc791039d3534e9dba.jpeg'"
|
|
|
|
|
:src="item.images || getImgUrl('wutu.jpeg')"
|
|
|
|
|
:preview-src-list="[
|
|
|
|
|
item.images || 'https://p119-minio-upload.ngsk.tech:7001/besure/998a6fc5d7da4ad079cc5afaa1ca5293917c17080c9805dc791039d3534e9dba.jpeg'
|
|
|
|
|
item.images || getImgUrl('wutu.jpeg')
|
|
|
|
|
]"
|
|
|
|
|
fit="cover"
|
|
|
|
|
preview-teleported
|
|
|
|
|
@ -857,6 +870,9 @@ const handleView = (row) => {
|
|
|
|
|
query: {id: row.id}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
const getImgUrl = (imgName) => {
|
|
|
|
|
return new URL(`/src/assets/imgs/${imgName}`, import.meta.url).href
|
|
|
|
|
}
|
|
|
|
|
/** 设备类型 列表 */
|
|
|
|
|
//defineOptions({name: 'DeviceLedger'})
|
|
|
|
|
const getEquipmentColor = (type) => {
|
|
|
|
|
@ -882,27 +898,6 @@ const getEquipmentIcon = (type) => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 工具函数
|
|
|
|
|
const getStatusTag = (status) => {
|
|
|
|
|
const tagMap = {
|
|
|
|
|
'运行': 'success',//running
|
|
|
|
|
'待机中': 'info',//standby
|
|
|
|
|
'故障中': 'danger',//fault
|
|
|
|
|
'报警中': 'warning',//maintenance
|
|
|
|
|
'离线': 'info'//stopped
|
|
|
|
|
}
|
|
|
|
|
return tagMap[status] || 'info'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getStatusText = (status) => {
|
|
|
|
|
const textMap = {
|
|
|
|
|
'运行': 'status-running',
|
|
|
|
|
'待机中': 'status-standby',
|
|
|
|
|
'故障中': 'status-fault',
|
|
|
|
|
'报警中': 'status-maintenance',
|
|
|
|
|
'离线': 'status-stopped'
|
|
|
|
|
}
|
|
|
|
|
return textMap[status] || '未知'
|
|
|
|
|
}
|
|
|
|
|
// 切换视图
|
|
|
|
|
const toggleView = () => {
|
|
|
|
|
|
|
|
|
|
@ -951,20 +946,93 @@ const queryParams = reactive({
|
|
|
|
|
const queryFormRef = ref() // 搜索的表单
|
|
|
|
|
const exportLoading = ref(false) // 导出的加载中
|
|
|
|
|
|
|
|
|
|
type DeviceOperatingStatusKey = 'running' | 'standby' | 'fault' | 'alarm' | 'offline'
|
|
|
|
|
type DeviceStatisticKey = 'total' | DeviceOperatingStatusKey
|
|
|
|
|
const deviceStatistics = reactive<Record<DeviceStatisticKey, number>>({
|
|
|
|
|
total: 0,
|
|
|
|
|
running: 0,
|
|
|
|
|
standby: 0,
|
|
|
|
|
fault: 0,
|
|
|
|
|
alarm: 0,
|
|
|
|
|
offline: 0
|
|
|
|
|
})
|
|
|
|
|
const deviceStatisticsItems = computed(() => [
|
|
|
|
|
{ key: 'total', label: '总数', value: deviceStatistics.total },
|
|
|
|
|
{ key: 'running', label: '运行数', value: deviceStatistics.running },
|
|
|
|
|
{ key: 'standby', label: '待机数', value: deviceStatistics.standby },
|
|
|
|
|
{ key: 'fault', label: '故障数', value: deviceStatistics.fault },
|
|
|
|
|
{ key: 'alarm', label: '报警数', value: deviceStatistics.alarm },
|
|
|
|
|
{ key: 'offline', label: '离线数', value: deviceStatistics.offline }
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
const normalizeDeviceOperatingStatus = (value: string | number | undefined): DeviceOperatingStatusKey => {
|
|
|
|
|
const text = String(value ?? '').trim().toLowerCase()
|
|
|
|
|
if (['运行', '运行中', 'running', 'run', '1'].includes(text)) return 'running'
|
|
|
|
|
if (['待机', '待机中', 'standby', 'idle', '2'].includes(text)) return 'standby'
|
|
|
|
|
if (['故障', '故障中', 'fault', 'error', '3'].includes(text)) return 'fault'
|
|
|
|
|
if (['报警', '报警中', 'alarm', 'warning', '4', '5'].includes(text)) return 'alarm'
|
|
|
|
|
return 'offline'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const operatingStatusLabelMap: Record<DeviceOperatingStatusKey, string> = {
|
|
|
|
|
running: '运行',
|
|
|
|
|
standby: '待机中',
|
|
|
|
|
fault: '故障中',
|
|
|
|
|
alarm: '报警中',
|
|
|
|
|
offline: '离线'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const operatingStatusTypeMap: Record<DeviceOperatingStatusKey, 'success' | 'info' | 'danger' | 'warning'> = {
|
|
|
|
|
running: 'success',
|
|
|
|
|
standby: 'info',
|
|
|
|
|
fault: 'danger',
|
|
|
|
|
alarm: 'warning',
|
|
|
|
|
offline: 'info'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const setDeviceStatistics = (rows: DeviceVO[] = []) => {
|
|
|
|
|
const nextStats: Record<DeviceStatisticKey, number> = {
|
|
|
|
|
total: rows.length,
|
|
|
|
|
running: 0,
|
|
|
|
|
standby: 0,
|
|
|
|
|
fault: 0,
|
|
|
|
|
alarm: 0,
|
|
|
|
|
offline: 0
|
|
|
|
|
}
|
|
|
|
|
rows.forEach((row) => {
|
|
|
|
|
const key = normalizeDeviceOperatingStatus(row.operatingStatus)
|
|
|
|
|
nextStats[key] += 1
|
|
|
|
|
})
|
|
|
|
|
Object.assign(deviceStatistics, nextStats)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getDeviceStatistics = async (totalCount = total.value) => {
|
|
|
|
|
const { pageNo, pageSize, ...params } = queryParams
|
|
|
|
|
const statisticsPageSize = Math.max(Number(totalCount) || 0, Number(pageSize) || 10, 1)
|
|
|
|
|
try {
|
|
|
|
|
const data = await DeviceApi.getDevicePage({
|
|
|
|
|
...params,
|
|
|
|
|
pageNo: 1,
|
|
|
|
|
pageSize: statisticsPageSize
|
|
|
|
|
})
|
|
|
|
|
const rows = Array.isArray(data) ? data : Array.isArray((data as any)?.list) ? (data as any).list : []
|
|
|
|
|
setDeviceStatistics(rows)
|
|
|
|
|
} catch {
|
|
|
|
|
setDeviceStatistics(list.value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getOperatingStatusLabel = (value: string | number | undefined) => {
|
|
|
|
|
const text = String(value ?? '').trim()
|
|
|
|
|
if (!text) return '离线'
|
|
|
|
|
return text
|
|
|
|
|
return text || operatingStatusLabelMap[normalizeDeviceOperatingStatus(value)]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getOperatingStatusType = (value: string | number | undefined) => {
|
|
|
|
|
const text = String(value ?? '').trim()
|
|
|
|
|
if (!text) return 'info'
|
|
|
|
|
if (text === '运行') return 'success'
|
|
|
|
|
if (text === '待机中') return 'info'
|
|
|
|
|
if (text === '故障中') return 'danger'
|
|
|
|
|
if (text === '报警中') return 'warning'
|
|
|
|
|
return 'info'
|
|
|
|
|
return operatingStatusTypeMap[normalizeDeviceOperatingStatus(value)]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getStatusText = (status: string | number | undefined) => {
|
|
|
|
|
return `status-${normalizeDeviceOperatingStatus(status)}`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const isDeviceEnabled = (row: DeviceVO) => {
|
|
|
|
|
@ -976,14 +1044,15 @@ const isDeviceEnabled = (row: DeviceVO) => {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleDeviceEnableChange = async (row: DeviceVO, value: boolean) => {
|
|
|
|
|
const handleDeviceEnableChange = async (row: DeviceVO, value: string | number | boolean) => {
|
|
|
|
|
if (!row.id) return
|
|
|
|
|
const enabled = value === true || value === 'true' || value === '1' || value === 1
|
|
|
|
|
const oldValue = (row as any).isEnable
|
|
|
|
|
;(row as any).isEnable = value
|
|
|
|
|
;(row as any).isEnable = enabled
|
|
|
|
|
try {
|
|
|
|
|
await DeviceApi.updateDeviceEnabled(row.id, value ? 'true' : 'false')
|
|
|
|
|
await DeviceApi.updateDeviceEnabled(row.id, enabled ? 'true' : 'false')
|
|
|
|
|
const name = (row as any).deviceName ?? (row as any).deviceCode ?? ''
|
|
|
|
|
const suffix = value ? '已启用' : '已停用'
|
|
|
|
|
const suffix = enabled ? '已启用' : '已停用'
|
|
|
|
|
if (name) {
|
|
|
|
|
message.success(`${name}${suffix}`)
|
|
|
|
|
} else {
|
|
|
|
|
@ -1009,6 +1078,7 @@ const getList = async (showLoading = true) => {
|
|
|
|
|
const data = await DeviceApi.getDevicePage(queryParams)
|
|
|
|
|
list.value = data.list
|
|
|
|
|
total.value = data.total
|
|
|
|
|
await getDeviceStatistics(data.total)
|
|
|
|
|
} finally {
|
|
|
|
|
if (showLoading) {
|
|
|
|
|
loading.value = false
|
|
|
|
|
@ -1025,6 +1095,7 @@ const getListOne = async (showLoading = true) => {
|
|
|
|
|
const data = await DeviceApi.getDevicePage(queryParams)
|
|
|
|
|
list.value = data.list
|
|
|
|
|
total.value = data.total
|
|
|
|
|
await getDeviceStatistics(data.total)
|
|
|
|
|
} finally {
|
|
|
|
|
if (showLoading) {
|
|
|
|
|
loading.value = false
|
|
|
|
|
@ -1972,6 +2043,71 @@ const handleShowDeviceAlarmHistory = async () => {
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
.device-statistics {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: repeat(6, minmax(0, 1fr));
|
|
|
|
|
gap: 10px;
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.device-statistics__item {
|
|
|
|
|
min-height: 72px;
|
|
|
|
|
padding: 12px 16px;
|
|
|
|
|
border: 1px solid #e4e7ed;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
background: linear-gradient(180deg, #ffffff 0%, #fafafa 100%);
|
|
|
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.device-statistics__label {
|
|
|
|
|
display: block;
|
|
|
|
|
color: #606266;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
line-height: 18px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.device-statistics__value {
|
|
|
|
|
display: block;
|
|
|
|
|
margin-top: 8px;
|
|
|
|
|
color: #303133;
|
|
|
|
|
font-size: 26px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
line-height: 30px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.device-statistics__item--running .device-statistics__value {
|
|
|
|
|
color: #67c23a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.device-statistics__item--fault .device-statistics__value {
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.device-statistics__item--alarm .device-statistics__value {
|
|
|
|
|
color: #e6a23c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.device-statistics__item--offline .device-statistics__value,
|
|
|
|
|
.device-statistics__item--standby .device-statistics__value {
|
|
|
|
|
color: #909399;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 1200px) {
|
|
|
|
|
.device-statistics {
|
|
|
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 640px) {
|
|
|
|
|
.device-statistics {
|
|
|
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.device-statistics__item {
|
|
|
|
|
padding: 10px 12px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.simple-grid-view {
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|