优化制品车间设备运行

main
liutao 2 days ago
parent 075dc313ab
commit 420b16bd16

@ -409,7 +409,7 @@ export default {
runningTime: 'Running Time (Today)',
standbyTime: 'Idle Time (Today)',
alarmTime: 'Alarm Time (Today)',
efficiency: 'Efficiency (Today)'
efficiency: 'Activation (Today)'
},
empty: 'No device operation data'
},

@ -409,7 +409,7 @@ export default {
runningTime: '运行时间(今日)',
standbyTime: '空闲时间(今日)',
alarmTime: '报警时间(今日)',
efficiency: '运行效率(今日)'
efficiency: '稼动率(今日)'
},
empty: '暂无设备运行数据'
},

@ -119,7 +119,12 @@ import { useFullscreen } from '@vueuse/core'
import * as echarts from 'echarts'
import type { EChartsOption } from 'echarts'
import { DeviceOperationOverviewApi } from '@/api/iot/deviceOperationOverview'
import type { DeviceOperationOverviewRespVO, DeviceOperationOverviewTimelineRowVO } from '@/api/iot/deviceOperationOverview'
import type {
DeviceOperationOverviewHourlyStatusVO,
DeviceOperationOverviewRespVO,
DeviceOperationOverviewTimelineRowVO
} from '@/api/iot/deviceOperationOverview'
import { DeviceApi, type DeviceVO } from '@/api/iot/device'
import { OrganizationApi } from '@/api/mes/organization'
defineOptions({ name: 'IotReportDashboard3' })
@ -128,6 +133,14 @@ const { t } = useI18n('Dashboard3')
type RunStatus = 'running' | 'standby' | 'fault' | 'offline'
interface DeviceStatusStatistics {
total: number
running: number
standby: number
fault: number
offline: number
}
interface OrganizationFilterItem {
id: string
parentId?: string | null
@ -159,6 +172,15 @@ const overviewData = ref<DeviceOperationOverviewRespVO>({
timelineRows: [],
totalDevices: 0
})
const last24HourlyStatus = ref<DeviceOperationOverviewHourlyStatusVO[]>([])
const deviceStatusStatistics = ref<DeviceStatusStatistics>({
total: 0,
running: 0,
standby: 0,
fault: 0,
offline: 0
})
const deviceOperatingStatusMap = ref<Record<string, RunStatus>>({})
const weekTrend = ref<{ date: string; rate: number }[]>([])
const detailPage = ref(1)
const detailPageSize = 8
@ -178,18 +200,6 @@ const statusText = computed<Record<RunStatus, string>>(() => ({
offline: t('Status.offline')
}))
const metricValueMap = computed(() => {
return overviewData.value.metrics.reduce<Record<string, number>>((acc, item) => {
acc[item.key] = Number(item.value) || 0
return acc
}, {})
})
const getMetricValue = (keys: string[]) => {
const foundKey = keys.find((key) => metricValueMap.value[key] !== undefined)
return foundKey ? metricValueMap.value[foundKey] : undefined
}
const calcDeviceRate = (count: number, total: number) => {
if (!total) return 0
return Number(((count / total) * 100).toFixed(1))
@ -248,7 +258,7 @@ const statusCards = computed(() => [
const detailRows = computed<DetailRow[]>(() => {
return overviewData.value.timelineRows.map((row) => {
const minutes = calcMinutes(row)
const status = getCurrentStatus(row)
const status = deviceOperatingStatusMap.value[String(row.id)] || getCurrentStatus(row)
return {
id: String(row.id),
name: row.name || '-',
@ -263,22 +273,14 @@ const detailRows = computed<DetailRow[]>(() => {
})
const totalDetailPages = computed(() => Math.max(1, Math.ceil(detailRows.value.length / detailPageSize)))
const runningDeviceCount = computed(
() => getMetricValue(['running', 'run', 'runningDevices']) ?? getRowsByStatus('running').length
)
const standbyDeviceCount = computed(
() => getMetricValue(['standby', 'idle', 'standbyDevices']) ?? getRowsByStatus('standby').length
)
const faultDeviceCount = computed(
() => getMetricValue(['fault', 'alarm', 'faultDevices']) ?? getRowsByStatus('fault').length
)
const offlineDeviceCount = computed(
() => getMetricValue(['offline', 'offlineDevices']) ?? getRowsByStatus('offline').length
)
const runningDeviceCount = computed(() => deviceStatusStatistics.value.running)
const standbyDeviceCount = computed(() => deviceStatusStatistics.value.standby)
const faultDeviceCount = computed(() => deviceStatusStatistics.value.fault)
const offlineDeviceCount = computed(() => deviceStatusStatistics.value.offline)
const onlineDeviceCount = computed(
() => runningDeviceCount.value + standbyDeviceCount.value + faultDeviceCount.value
)
const totalDeviceCount = computed(() => onlineDeviceCount.value + offlineDeviceCount.value)
const totalDeviceCount = computed(() => deviceStatusStatistics.value.total)
const pagedRows = computed(() => {
const start = (detailPage.value - 1) * detailPageSize
return detailRows.value.slice(start, start + detailPageSize)
@ -290,15 +292,22 @@ const alarmDevices = computed(() => {
.sort((a, b) => b.alarmMinutes - a.alarmMinutes)
.slice(0, 2)
})
const hourlyRates = computed(() =>
overviewData.value.hourlyStatus.map((item) => {
const total = item.running + item.standby + item.fault + item.offline
return {
hour: item.hour,
rate: total > 0 ? Number(((item.running / total) * 100).toFixed(1)) : 0
}
})
)
const hourlyRates = computed(() => {
const rateMap = last24HourlyStatus.value.reduce<Record<string, number>>((acc, item) => {
const rate = getHourlyRunningRate(item)
getHourlyKeyCandidates(item.hour).forEach((key) => {
acc[key] = rate
})
return acc
}, {})
return getLast24HourBuckets().map((time) => ({
hour: time.format('MM-DD HH:00'),
rate: getHourlyKeyCandidates(time.format('YYYY-MM-DD HH:00:00'))
.map((key) => rateMap[key])
.find((rate) => rate !== undefined) ?? 0
}))
})
const todayAverageRate = computed(() => average(hourlyRates.value.map((item) => item.rate)))
const sevenDayAverageRate = computed(() => average(weekTrend.value.map((item) => item.rate)))
@ -319,7 +328,92 @@ const average = (values: number[]) => {
return Number((valid.reduce((sum, item) => sum + item, 0) / valid.length).toFixed(1))
}
const getRowsByStatus = (status: RunStatus) => detailRows.value.filter((row) => row.status === status)
const getHourlyRunningRate = (item: DeviceOperationOverviewHourlyStatusVO) => {
const total = item.running + item.standby + item.fault + item.offline
return total > 0 ? Number(((item.running / total) * 100).toFixed(1)) : 0
}
const getHourlyKeyCandidates = (hour: string) => {
const text = String(hour || '').trim()
const candidates = new Set<string>()
if (text) candidates.add(text)
const parsed = dayjs(text)
if (parsed.isValid()) {
candidates.add(parsed.format('YYYY-MM-DD HH:00:00'))
candidates.add(parsed.format('YYYY-MM-DD HH:00'))
candidates.add(parsed.format('MM-DD HH:00'))
candidates.add(parsed.format('HH:00'))
}
const hourMatch = text.match(/(\d{1,2}):00/)
if (hourMatch) {
candidates.add(`${hourMatch[1].padStart(2, '0')}:00`)
}
return Array.from(candidates)
}
const normalizeDeviceOperatingStatus = (value: string | number | undefined): RunStatus => {
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'
return 'offline'
}
const setDeviceStatusStatistics = (rows: DeviceVO[] = []) => {
const nextStats: DeviceStatusStatistics = {
total: rows.length,
running: 0,
standby: 0,
fault: 0,
offline: 0
}
const nextStatusMap: Record<string, RunStatus> = {}
rows.forEach((row) => {
const status = normalizeDeviceOperatingStatus(row.operatingStatus)
nextStats[status] += 1
if (row.id != null) {
nextStatusMap[String(row.id)] = status
}
})
deviceStatusStatistics.value = nextStats
deviceOperatingStatusMap.value = nextStatusMap
}
const getDevicePageRows = (data: any): DeviceVO[] => {
return Array.isArray(data) ? data : Array.isArray(data?.list) ? data.list : []
}
const refreshDeviceStatusStatistics = async () => {
const ids = getDeviceIds().join(',')
const baseParams = {
...(ids ? { ids } : {})
}
try {
const firstPage = await DeviceApi.getDevicePage({
...baseParams,
pageNo: 1,
pageSize: 1
})
const firstRows = getDevicePageRows(firstPage)
const total = Number((firstPage as any)?.total) || firstRows.length
const pageSize = Math.max(total, firstRows.length, 1)
const data = pageSize === firstRows.length
? firstPage
: await DeviceApi.getDevicePage({
...baseParams,
pageNo: 1,
pageSize
})
setDeviceStatusStatistics(getDevicePageRows(data))
} catch {
setDeviceStatusStatistics([])
}
}
const getCurrentStatus = (row: DeviceOperationOverviewTimelineRowVO): RunStatus => {
const currentHour = dayjs().hour() + dayjs().minute() / 60
@ -387,6 +481,24 @@ const buildParams = (startTime: string, endTime: string, pageSize = 1000) => ({
timelinePageSize: pageSize
})
const getDayRange = (date = dayjs()) => ({
start: date.startOf('day').format('YYYY-MM-DD HH:mm:ss'),
end: date.add(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
})
const getLast24HoursRange = () => {
const end = dayjs().startOf('hour')
return {
start: end.subtract(24, 'hour').format('YYYY-MM-DD HH:mm:ss'),
end: end.format('YYYY-MM-DD HH:mm:ss')
}
}
const getLast24HourBuckets = () => {
const end = dayjs().startOf('hour')
return Array.from({ length: 24 }, (_, index) => end.subtract(23 - index, 'hour'))
}
const loadOrganizationList = async () => {
const data = await OrganizationApi.getOrganizationList()
organizationList.value = Array.isArray(data)
@ -400,8 +512,7 @@ const loadOrganizationList = async () => {
}
const refreshTodayData = async () => {
const start = dayjs().startOf('day').format('YYYY-MM-DD HH:mm:ss')
const end = dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss')
const { start, end } = getDayRange()
const response = await DeviceOperationOverviewApi.getRunOverview(buildParams(start, end))
overviewData.value = {
metrics: response?.metrics || [],
@ -414,11 +525,18 @@ const refreshTodayData = async () => {
lastUpdateTime.value = dayjs().format('YYYY/M/D HH:mm:ss')
}
const refreshLast24HourTrend = async () => {
const { start, end } = getLast24HoursRange()
const response = await DeviceOperationOverviewApi.getRunOverview(buildParams(start, end))
last24HourlyStatus.value = response?.hourlyStatus || []
}
const refreshWeekTrend = async () => {
const requests = Array.from({ length: 7 }).map((_, index) => {
const date = dayjs().subtract(6 - index, 'day')
const { start, end } = getDayRange(date)
return DeviceOperationOverviewApi.getRunOverview(
buildParams(date.startOf('day').format('YYYY-MM-DD HH:mm:ss'), date.endOf('day').format('YYYY-MM-DD HH:mm:ss'), 1)
buildParams(start, end, 1)
).then((res) => {
const running = res?.summary?.find((item) => item.status === 'running')?.percent || 0
return {
@ -431,7 +549,7 @@ const refreshWeekTrend = async () => {
}
const refreshData = async () => {
await refreshTodayData()
await Promise.all([refreshTodayData(), refreshDeviceStatusStatistics(), refreshLast24HourTrend()])
await refreshWeekTrend()
renderCharts()
}

Loading…
Cancel
Save