From 84101b7866b2cea06d9f99ce031fcbdfce00be02 Mon Sep 17 00:00:00 2001 From: liutao <790864623@qq.com> Date: Fri, 8 May 2026 17:04:37 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=BE=E5=A4=87=E8=BF=90=E8=A1=8C=E6=A6=82?= =?UTF-8?q?=E8=A7=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/StatusDistributionChart.vue | 11 ++- src/views/iot/runoverview/components/types.ts | 1 + src/views/iot/runoverview/index.vue | 51 ++++++++-- src/views/iot/runoverview/mock.ts | 94 +------------------ 4 files changed, 51 insertions(+), 106 deletions(-) diff --git a/src/views/iot/runoverview/components/StatusDistributionChart.vue b/src/views/iot/runoverview/components/StatusDistributionChart.vue index 2b9ec06d..29280eb2 100644 --- a/src/views/iot/runoverview/components/StatusDistributionChart.vue +++ b/src/views/iot/runoverview/components/StatusDistributionChart.vue @@ -52,6 +52,7 @@ const Echart = EchartChart const props = defineProps<{ hourlyStatus: HourlyStatusItem[] summary: StatusSummaryItem[] + summaryTotalHours?: number }>() const { t } = useI18n() @@ -137,11 +138,11 @@ const pieOption = computed(() => ({ tooltip: { trigger: 'item', formatter: '{b}: {c}%' }, graphic: [ { - type: 'text', - left: 'center', - top: '42%', - style: { - text: `${t('DataCollection.RunOverview.totalTimeLabel')}\n24.00 h`, + type: 'text', + left: 'center', + top: '42%', + style: { + text: `${t('DataCollection.RunOverview.totalTimeLabel')}\n${(props.summaryTotalHours ?? 0).toFixed(2)} h`, textAlign: 'center', fill: '#101828', fontSize: 14, diff --git a/src/views/iot/runoverview/components/types.ts b/src/views/iot/runoverview/components/types.ts index fef23cdc..1cf1dacc 100644 --- a/src/views/iot/runoverview/components/types.ts +++ b/src/views/iot/runoverview/components/types.ts @@ -69,6 +69,7 @@ export interface RunOverviewData { metrics: RunOverviewMetric[] hourlyStatus: HourlyStatusItem[] summary: StatusSummaryItem[] + summaryTotalHours: number timelineRows: DeviceTimelineRow[] totalDevices: number } diff --git a/src/views/iot/runoverview/index.vue b/src/views/iot/runoverview/index.vue index 43695a85..7d70e47d 100644 --- a/src/views/iot/runoverview/index.vue +++ b/src/views/iot/runoverview/index.vue @@ -27,7 +27,11 @@ - + import dayjs from 'dayjs' import { useFullscreen } from '@vueuse/core' +import { DeviceOperationOverviewApi } from '@/api/iot/deviceOperationOverview' import { OrganizationApi } from '@/api/mes/organization' import { handleTree } from '@/utils/tree' import OverviewFilterBar from './components/OverviewFilterBar.vue' import OverviewMetricCards from './components/OverviewMetricCards.vue' import OperationTimelineChart from './components/OperationTimelineChart.vue' import StatusDistributionChart from './components/StatusDistributionChart.vue' -import { buildDefaultQueryParams, buildRunOverviewData } from './mock' +import { buildDefaultQueryParams, buildRunOverviewTimelineData } from './mock' import type { OrganizationFilterItem, OrganizationTreeOption, @@ -144,10 +149,36 @@ const collectDeviceOptionsByGroup = (groupId?: string) => { } const deviceOptions = computed(() => collectDeviceOptionsByGroup(queryParams.value.groupId)) -const overviewData = ref(buildRunOverviewData(queryParams.value, deviceOptions.value)) +const overviewData = ref({ + metrics: [], + hourlyStatus: [], + summary: [], + summaryTotalHours: 0, + timelineRows: [], + totalDevices: 0 +}) + +const currentDeviceIds = computed(() => + queryParams.value.deviceId.length > 0 ? queryParams.value.deviceId : deviceOptions.value.map((item) => item.value) +) -const refreshData = () => { - overviewData.value = buildRunOverviewData(queryParams.value, deviceOptions.value) +const buildOverviewRequestParams = () => ({ + ids: currentDeviceIds.value.join(','), + startTime: queryParams.value.timeRange[0], + endTime: queryParams.value.timeRange[1] +}) + +const refreshData = async () => { + const response = await DeviceOperationOverviewApi.getRunOverview(buildOverviewRequestParams()) + const timelineData = buildRunOverviewTimelineData(queryParams.value, deviceOptions.value) + overviewData.value = { + metrics: response?.metrics || [], + hourlyStatus: response?.hourlyStatus || [], + summary: response?.summary || [], + summaryTotalHours: response?.summaryTotalHours || 0, + timelineRows: timelineData.timelineRows, + totalDevices: timelineData.totalDevices + } const maxPage = Math.max(1, Math.ceil(overviewData.value.totalDevices / pageSize.value)) if (pageNo.value > maxPage) pageNo.value = maxPage } @@ -156,22 +187,22 @@ const handleQuickRangeChange = (key: QuickRangeKey) => { queryParams.value = { ...queryParams.value, quickRange: key, - timeRange: key === 'custom' ? queryParams.value.timeRange : createDateRangeByQuickKey(key) + timeRange: createDateRangeByQuickKey(key) } pageNo.value = 1 - refreshData() + void refreshData() } const handleQuery = () => { pageNo.value = 1 - refreshData() + void refreshData() } const resetQuery = () => { queryParams.value = buildDefaultQueryParams() pageNo.value = 1 pageSize.value = 10 - refreshData() + void refreshData() } const handleExport = () => { @@ -220,7 +251,7 @@ watch( onMounted(async () => { await getOrganizationOptions() - refreshData() + await refreshData() }) diff --git a/src/views/iot/runoverview/mock.ts b/src/views/iot/runoverview/mock.ts index 20596bfd..b5468582 100644 --- a/src/views/iot/runoverview/mock.ts +++ b/src/views/iot/runoverview/mock.ts @@ -1,13 +1,5 @@ import dayjs from 'dayjs' -import type { - DeviceTimelineRow, - HourlyStatusItem, - OverviewOption, - RunOverviewData, - RunOverviewMetric, - RunOverviewQueryParams, - RunStatus -} from './components/types' +import type { DeviceTimelineRow, OverviewOption, RunOverviewData, RunOverviewQueryParams, RunStatus } from './components/types' const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss' @@ -81,93 +73,13 @@ const toTimelineRows = (deviceOptions: OverviewOption[]): DeviceTimelineRow[] => segments: shiftTimeline(BASE_SEGMENTS, TIMELINE_OFFSETS[index % TIMELINE_OFFSETS.length]) })) -const toHourlyStatus = (summaryFactor: number): HourlyStatusItem[] => - Array.from({ length: 24 }, (_, hour) => { - const runningBase = 74 + Math.sin((hour / 24) * Math.PI * 3) * 14 + summaryFactor * 2 - const standbyBase = 10 + Math.cos((hour / 24) * Math.PI * 4) * 7 - const faultBase = 2 + Math.max(0, Math.sin((hour - 5) / 2.2)) * 5 - - const running = Math.max(48, Math.min(88, Number(runningBase.toFixed(2)))) - const standby = Math.max(4, Math.min(26, Number(standbyBase.toFixed(2)))) - const fault = Math.max(1, Math.min(8, Number(faultBase.toFixed(2)))) - const offline = Number(Math.max(4, 100 - running - standby - fault).toFixed(2)) - - return { - hour: `${String(hour).padStart(2, '0')}:00`, - running, - standby, - fault, - offline - } - }) - -const createMetrics = (summaryFactor: number): RunOverviewMetric[] => [ - { - key: 'utilizationRate', - icon: 'ep:pie-chart', - value: Number((75.42 + summaryFactor * 1.2).toFixed(2)), - unit: '%', - change: 4.32 - }, - { - key: 'powerOnRate', - icon: 'ep:video-play', - value: Number((90.12 + summaryFactor * 0.7).toFixed(2)), - unit: '%', - change: 2.15 - }, - { - key: 'faultRate', - icon: 'ep:warning', - value: Number(Math.max(1.5, 3.21 - summaryFactor * 0.35).toFixed(2)), - unit: '%', - change: -1.03 - }, - { - key: 'standbyRate', - icon: 'ep:timer', - value: Number(Math.max(4, 6.67 - summaryFactor * 0.25).toFixed(2)), - unit: '%', - change: -1.14 - } -] - -const createSummary = (summaryFactor: number) => { - const running = Number((75.42 + summaryFactor * 1.2).toFixed(2)) - const standby = Number(Math.max(4, 6.67 - summaryFactor * 0.25).toFixed(2)) - const fault = Number(Math.max(1.5, 3.21 - summaryFactor * 0.35).toFixed(2)) - const offline = Number((100 - running - standby - fault).toFixed(2)) - - return [ - { status: 'running' as const, percent: running, hours: Number(((24 * running) / 100).toFixed(2)) }, - { status: 'standby' as const, percent: standby, hours: Number(((24 * standby) / 100).toFixed(2)) }, - { status: 'fault' as const, percent: fault, hours: Number(((24 * fault) / 100).toFixed(2)) }, - { status: 'offline' as const, percent: offline, hours: Number(((24 * offline) / 100).toFixed(2)) } - ] -} - -export const buildRunOverviewData = ( +export const buildRunOverviewTimelineData = ( query: RunOverviewQueryParams, deviceOptions: OverviewOption[] = FALLBACK_DEVICE_OPTIONS -): RunOverviewData => { - const summaryFactor = - query.quickRange === 'today' - ? 0 - : query.quickRange === 'yesterday' - ? -0.8 - : query.quickRange === 'last7Days' - ? 1.1 - : query.quickRange === 'last30Days' - ? 0.45 - : 0.15 - +): Pick => { const rows = toTimelineRows(deviceOptions.length > 0 ? deviceOptions : FALLBACK_DEVICE_OPTIONS) const filteredRows = query.deviceId.length > 0 ? rows.filter((row) => query.deviceId.includes(row.id)) : rows - return { - metrics: createMetrics(summaryFactor), - hourlyStatus: toHourlyStatus(summaryFactor), - summary: createSummary(summaryFactor), timelineRows: filteredRows, totalDevices: filteredRows.length }