From 3745ef5bbca5181e0bfc6d8fb582bcd19155bb3a Mon Sep 17 00:00:00 2001
From: liutao <790864623@qq.com>
Date: Thu, 14 May 2026 15:30:38 +0800
Subject: [PATCH 1/3] =?UTF-8?q?=E8=83=BD=E6=BA=90=E6=A6=82=E8=A7=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/api/mes/energydevice/index.ts | 59 +++++
src/views/mes/energyOverview/index.vue | 349 ++++++++++---------------
2 files changed, 190 insertions(+), 218 deletions(-)
diff --git a/src/api/mes/energydevice/index.ts b/src/api/mes/energydevice/index.ts
index 0ea5247f..feccb85a 100644
--- a/src/api/mes/energydevice/index.ts
+++ b/src/api/mes/energydevice/index.ts
@@ -42,6 +42,61 @@ export interface EnergyDeviceDataRecordVO {
latestDataTime?: string
}
+export interface EnergyOverviewMetricVO {
+ key: string
+ label: string
+ value: string
+ unit?: string
+ subLabel?: string
+ subValue?: string
+ change?: string
+ down?: boolean
+}
+
+export interface EnergyOverviewTrendVO {
+ unit?: string
+ xAxis: string[]
+ data: string[]
+}
+
+export interface EnergyOverviewRegionItemVO {
+ name: string
+ value: string
+ percent: string
+}
+
+export interface EnergyOverviewRegionVO {
+ unit?: string
+ totalValue: string
+ items: EnergyOverviewRegionItemVO[]
+}
+
+export interface EnergyOverviewRankVO {
+ id: number
+ name: string
+ region: string
+ value: string
+}
+
+export interface EnergyOverviewDetailVO {
+ id: number
+ name: string
+ energyType: string
+ region: string
+ value: string
+ startTime: string
+ endTime: string
+}
+
+export interface EnergyOverviewRespVO {
+ metrics: EnergyOverviewMetricVO[]
+ trendChart: EnergyOverviewTrendVO
+ regionChart: EnergyOverviewRegionVO
+ rankList: EnergyOverviewRankVO[]
+ total: number
+ detailList: EnergyOverviewDetailVO[]
+}
+
// 能源设备 API
export const EnergyDeviceApi = {
// 查询能源设备分页
@@ -66,6 +121,10 @@ export const EnergyDeviceApi = {
return await request.get({ url: `/mes/energy-device/queryDataRecords`, params })
},
+ queryOverviewData: async (params: any) => {
+ return await request.get({ url: `/mes/energy-device/queryOverviewData`, params })
+ },
+
exportQueryDataRecords: async (params: any) => {
return await request.download({ url: `/mes/energy-device/record-export-excel`, params })
},
diff --git a/src/views/mes/energyOverview/index.vue b/src/views/mes/energyOverview/index.vue
index ea7d7c2f..a674c335 100644
--- a/src/views/mes/energyOverview/index.vue
+++ b/src/views/mes/energyOverview/index.vue
@@ -9,7 +9,13 @@
label-width="auto"
>
-
+
@@ -63,7 +69,7 @@
{{ item.label }}
{{ item.value }}
- {{ item.unit }}
+ {{ item.unit }}
{{ item.subLabel }}
@@ -85,14 +91,6 @@
能源用量趋势
-
-
-
-
-
-
-
-
@@ -104,14 +102,6 @@
区域能耗占比
-
-
-
-
-
-
-
-
@@ -176,6 +166,14 @@
import { EChartsOption } from 'echarts'
import { Echart } from '@/components/Echart'
import { EnergyTypeApi, EnergyTypeVO } from '@/api/mes/energytype'
+import {
+ EnergyDeviceApi,
+ EnergyOverviewDetailVO,
+ EnergyOverviewMetricVO,
+ EnergyOverviewRankVO,
+ EnergyOverviewRespVO
+} from '@/api/mes/energydevice'
+import {OrganizationApi, OrganizationVO} from "@/api/mes/organization";
defineOptions({ name: 'EnergyOverview' })
@@ -192,24 +190,12 @@ interface MetricCard {
subValue?: string
}
-interface DetailRow {
- id: number
- name: string
- energyType: string
- region: string
- value: string
- startTime: string
- endTime: string
-}
+type DetailRow = EnergyOverviewDetailVO
const message = useMessage()
const defaultTimeRange = ['2026-05-04 00:00:00', '2026-05-05 23:59:59']
-const orgOptions = [
- { label: '成型系统', value: 1 },
- { label: '蛋托线01', value: 2 },
- { label: '烘干系统', value: 3 }
-]
+const orgOptions = ref<{ label: string; value: string | number; raw?: OrganizationVO }[]>([])
const loading = ref(false)
const queryFormRef = ref()
@@ -224,55 +210,19 @@ const queryParams = reactive({
})
const metricCards = ref([])
-const rankList = ref([
- { name: '蛋托成型柜用电量', region: '成型系统', value: '2,139.09' },
- { name: '蛋托线真空柜用电量', region: '蛋托线01', value: '0' },
- { name: '蛋托干燥柜用电量', region: '烘干系统', value: '0' },
- { name: '蛋托线其它用电量', region: '蛋托线01', value: '0' },
- { name: '烘干系统其它用电量', region: '烘干系统', value: '0' }
-])
-const detailList = ref([])
+const rankList = ref([])
const pageDetailList = ref([])
const total = ref(0)
const hasEnergyTypes = computed(() => energyTypeOptions.value.length > 0)
const selectedEnergyType = computed(() =>
energyTypeOptions.value.find((item) => item.id === queryParams.energyTypeId)
)
-const selectedEnergyName = computed(() => selectedEnergyType.value?.name || '电')
const selectedEnergyUnit = computed(() => selectedEnergyType.value?.unit || 'kWh')
-const selectedUnitConsumptionUnit = computed(() => `${selectedEnergyUnit.value}/件`)
-
-const hours = [
- '00:00',
- '01:00',
- '02:00',
- '03:00',
- '04:00',
- '05:00',
- '06:00',
- '07:00',
- '08:00',
- '09:00',
- '10:00',
- '11:00',
- '12:00',
- '13:00',
- '14:00',
- '15:00',
- '16:00',
- '17:00',
- '18:00',
- '19:00',
- '20:00',
- '21:00',
- '22:00'
-]
-const trendData = [90, 80, 72, 75, 74, 85, 105, 116, 120, 112, 123, 127, 122, 146, 156.8, 147, 116, 94, 88, 102, 103, 116, 106]
-const regionData = [
- { name: '成型系统', value: 2139.09 },
- { name: '蛋托线01', value: 0 },
- { name: '烘干系统', value: 0 }
-]
+
+const trendXAxis = ref([])
+const trendSeries = ref([])
+const regionItems = ref<{ name: string; value: number; percent: string }[]>([])
+const regionTotal = ref('0')
const trendChartOptions = reactive({
color: ['#2f7df6'],
@@ -280,12 +230,12 @@ const trendChartOptions = reactive({
trigger: 'axis',
formatter: (params: any) => {
const item = params?.[0]
- return `${item.axisValue}
用电量:${item.data} kWh`
+ return `${item?.axisValue || ''}
用量:${item?.data || 0} ${selectedEnergyUnit.value}`
}
},
legend: {
top: 4,
- data: ['用电量 (kWh)']
+ data: ['用量']
},
grid: {
left: 24,
@@ -297,25 +247,23 @@ const trendChartOptions = reactive({
xAxis: {
type: 'category',
boundaryGap: false,
- name: '时间(小时)',
+ name: '时间',
nameLocation: 'middle',
nameGap: 28,
- data: hours,
+ data: trendXAxis.value,
axisLine: { lineStyle: { color: '#dcdfe6' } },
axisLabel: { color: '#606266' }
},
yAxis: {
type: 'value',
- name: 'kWh',
+ name: selectedEnergyUnit.value,
min: 0,
- max: 180,
- interval: 30,
axisLabel: { color: '#606266' },
splitLine: { lineStyle: { color: '#e8edf5' } }
},
series: [
{
- name: '用电量 (kWh)',
+ name: '用量',
type: 'line',
smooth: true,
symbol: 'circle',
@@ -334,21 +282,16 @@ const trendChartOptions = reactive({
]
}
},
- data: trendData,
- markPoint: {
- symbolSize: 48,
- label: { color: '#2f7df6', formatter: '{c}' },
- data: [{ type: 'max', name: '峰值' }]
- }
+ data: trendSeries.value
}
]
-}) as EChartsOption
+})
const regionPieOptions = reactive({
- color: ['#2f7df6', '#52c41a', '#faad14'],
+ color: ['#2f7df6', '#52c41a', '#faad14', '#13c2c2', '#fa8c16'],
tooltip: {
trigger: 'item',
- formatter: '{b}
{c} kWh ({d}%)'
+ formatter: `{b}
{c} ${selectedEnergyUnit.value} ({d}%)`
},
legend: {
orient: 'vertical',
@@ -357,10 +300,10 @@ const regionPieOptions = reactive({
itemWidth: 12,
itemHeight: 12,
formatter: (name: string) => {
- const item = regionData.find((row) => row.name === name)
+ const item = regionItems.value.find((row) => row.name === name)
const value = item?.value ?? 0
- const percent = value > 0 ? '100.00' : '0.00'
- return `${name} ${value.toLocaleString()} kWh (${percent}%)`
+ const percent = item?.percent ?? '0.00'
+ return `${name} ${value.toLocaleString()} ${selectedEnergyUnit.value} (${percent}%)`
}
},
series: [
@@ -373,7 +316,7 @@ const regionPieOptions = reactive({
label: {
show: true,
position: 'center',
- formatter: '总用电量\n{total|2,139.09 kWh}',
+ formatter: `总用量\n{total|${regionTotal.value} ${selectedEnergyUnit.value}}`,
color: '#303133',
rich: {
total: {
@@ -385,116 +328,93 @@ const regionPieOptions = reactive({
}
},
labelLine: { show: false },
- data: regionData
+ data: regionItems.value
}
]
-}) as EChartsOption
-
-const buildMetrics = () => {
- metricCards.value = [
- {
- key: 'total',
- label: '总用电量',
- value: '2,139.09',
- unit: selectedEnergyUnit.value,
- icon: 'ep:lightning',
- theme: 'blue',
- subLabel: '较昨日',
- change: '12.53%'
- },
- {
- key: 'today',
- label: '今日用电量',
- value: '860.32',
- unit: selectedEnergyUnit.value,
- icon: 'ep:calendar',
- theme: 'green',
- subLabel: '较昨日',
- change: '12.15%'
- },
- {
- key: 'peak',
- label: '峰值用电',
- value: '156.8',
- unit: selectedEnergyUnit.value,
- icon: 'ep:histogram',
- theme: 'purple',
- subLabel: '时间:',
- subValue: '2026-05-04 14:00 ~ 15:00'
- },
- {
- key: 'unit',
- label: '单位产量能耗',
- value: '0.38',
- unit: selectedUnitConsumptionUnit.value,
- icon: 'ep:orange',
- theme: 'orange',
- subLabel: '较昨日',
- change: '5.21%',
- down: true
- },
- {
- key: 'region',
- label: '最大耗能区域',
- value: '成型系统',
- unit: '',
- icon: 'ep:pie-chart',
- theme: 'cyan',
- subLabel: '占比:',
- subValue: '100.00%'
- }
- ]
-}
+})
-const buildDetails = () => {
- const timeRange = queryParams.timeRange?.length === 2 ? queryParams.timeRange : defaultTimeRange
- detailList.value = [
- {
- id: 1,
- name: '蛋托线真空柜用电量',
- energyType: selectedEnergyName.value,
- region: '蛋托线01',
- value: '0',
- startTime: timeRange[0],
- endTime: timeRange[1]
- },
- {
- id: 2,
- name: '蛋托成型柜用电量',
- energyType: selectedEnergyName.value,
- region: '成型系统',
- value: '2,139.09',
- startTime: timeRange[0],
- endTime: timeRange[1]
- },
- {
- id: 3,
- name: '蛋托干燥柜用电量',
- energyType: selectedEnergyName.value,
- region: '烘干系统',
- value: '0',
- startTime: timeRange[0],
- endTime: timeRange[1]
+const metricThemeMap: Record = {
+ total: { icon: 'ep:lightning', theme: 'blue' },
+ deviceCount: { icon: 'ep:cpu', theme: 'green' },
+ topDevice: { icon: 'ep:histogram', theme: 'purple' },
+ topRegion: { icon: 'ep:pie-chart', theme: 'cyan' },
+ range: { icon: 'ep:calendar', theme: 'orange' }
+}
+
+const normalizeMetricCards = (metrics: EnergyOverviewMetricVO[]) => {
+ metricCards.value = metrics.map((item) => ({
+ key: item.key,
+ label: item.label,
+ value: item.value,
+ unit: item.unit || '',
+ icon: metricThemeMap[item.key]?.icon || 'ep:data-line',
+ theme: metricThemeMap[item.key]?.theme || 'blue',
+ subLabel: item.subLabel || '',
+ subValue: item.subValue || '',
+ change: item.change,
+ down: item.down
+ }))
+}
+
+const updateCharts = (data: EnergyOverviewRespVO) => {
+ trendXAxis.value = data.trendChart?.xAxis || []
+ trendSeries.value = (data.trendChart?.data || []).map((item) => Number(item) || 0)
+ regionItems.value = (data.regionChart?.items || []).map((item) => ({
+ name: item.name,
+ value: Number(item.value) || 0,
+ percent: item.percent
+ }))
+ regionTotal.value = data.regionChart?.totalValue || '0'
+
+ trendChartOptions.xAxis = {
+ ...(trendChartOptions.xAxis as any),
+ data: trendXAxis.value
+ }
+ trendChartOptions.yAxis = {
+ ...(trendChartOptions.yAxis as any),
+ name: selectedEnergyUnit.value
+ }
+ if (Array.isArray(trendChartOptions.series) && trendChartOptions.series[0]) {
+ ;(trendChartOptions.series[0] as any).data = trendSeries.value
+ }
+ if (Array.isArray(regionPieOptions.series) && regionPieOptions.series[0]) {
+ ;(regionPieOptions.series[0] as any).data = regionItems.value
+ ;(regionPieOptions.series[0] as any).label = {
+ ...(regionPieOptions.series[0] as any).label,
+ formatter: `总用量\n{total|${regionTotal.value} ${selectedEnergyUnit.value}}`
}
- ]
- total.value = detailList.value.length
+ }
}
-const getList = () => {
+const getList = async () => {
if (!hasEnergyTypes.value) {
metricCards.value = []
- detailList.value = []
+ rankList.value = []
pageDetailList.value = []
total.value = 0
return
}
loading.value = true
- buildMetrics()
- buildDetails()
- const start = (queryParams.pageNo - 1) * queryParams.pageSize
- pageDetailList.value = detailList.value.slice(start, start + queryParams.pageSize)
- loading.value = false
+ try {
+ const timeRange = queryParams.timeRange?.length === 2 ? queryParams.timeRange : defaultTimeRange
+ const res = await EnergyDeviceApi.queryOverviewData({
+ orgId: queryParams.orgId,
+ energyTypeId: queryParams.energyTypeId,
+ startTime: timeRange[0],
+ endTime: timeRange[1],
+ pageNo: queryParams.pageNo,
+ pageSize: queryParams.pageSize
+ })
+ const data = ((res as any)?.data || res) as EnergyOverviewRespVO
+ normalizeMetricCards(data.metrics || [])
+ rankList.value = data.rankList || []
+ pageDetailList.value = data.detailList || []
+ total.value = data.total || 0
+ updateCharts(data)
+ } finally {
+ loading.value = false
+ }
}
const normalizeEnergyTypeList = (data: unknown): EnergyTypeVO[] => {
@@ -508,14 +428,7 @@ const normalizeEnergyTypeList = (data: unknown): EnergyTypeVO[] => {
return []
}
-const getDefaultEnergyType = (list: EnergyTypeVO[]) => {
- return (
- list.find((item) => item.name === '电') ||
- list.find((item) => item.name === '水') ||
- list.find((item) => item.name === '气') ||
- list[0]
- )
-}
+const getDefaultEnergyType = (list: EnergyTypeVO[]) => list[0]
const getEnergyTypes = async () => {
try {
@@ -531,10 +444,6 @@ const getEnergyTypes = async () => {
}
const handleQuery = () => {
- if (!hasEnergyTypes.value) {
- getList()
- return
- }
queryParams.pageNo = 1
getList()
}
@@ -547,11 +456,28 @@ const resetQuery = () => {
handleQuery()
}
-const handleExport = () => {
- message.info('示例页暂未接入导出接口')
+const handleExport = async () => {
+ const timeRange = queryParams.timeRange?.length === 2 ? queryParams.timeRange : defaultTimeRange
+ await EnergyDeviceApi.exportQueryDataRecords({
+ orgId: queryParams.orgId,
+ startTime: timeRange[0],
+ endTime: timeRange[1]
+ })
+ message.success('导出已发起')
+}
+
+const loadOrgOptions = async () => {
+ if (orgOptions.value.length) return
+ const data: any = await OrganizationApi.getOrganizationList({})
+ const rows = (Array.isArray(data) ? data : data?.list ?? data?.data ?? []) as OrganizationVO[]
+ orgOptions.value = rows
+ .filter((r) => r?.id !== undefined && r?.name)
+ .map((r) => ({ label: r.name, value: r.id, raw: r }))
}
+
onMounted(async () => {
+ await loadOrgOptions()
await getEnergyTypes()
if (hasEnergyTypes.value) {
getList()
@@ -705,19 +631,6 @@ onMounted(async () => {
color: var(--el-color-primary-light-3);
}
-.panel-actions {
- display: inline-flex;
- align-items: center;
- gap: 4px;
-
- .el-button {
- width: 30px;
- height: 30px;
- padding: 0;
- border: 1px solid var(--el-border-color-light);
- }
-}
-
.rank-index {
display: inline-flex;
width: 22px;
From 9b82f41b375c85c81d1c006a815eeaaafa948c55 Mon Sep 17 00:00:00 2001
From: liutao <790864623@qq.com>
Date: Thu, 14 May 2026 15:47:08 +0800
Subject: [PATCH 2/3] =?UTF-8?q?=E8=83=BD=E8=80=97=E6=A6=82=E8=A7=88?=
=?UTF-8?q?=E7=9A=84=E4=B8=AD=E8=8B=B1=E6=96=87=E5=88=87=E6=8D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/locales/en.ts | 34 ++++++++++
src/locales/zh-CN.ts | 34 ++++++++++
src/views/mes/energyOverview/index.vue | 88 +++++++++++++++-----------
3 files changed, 120 insertions(+), 36 deletions(-)
diff --git a/src/locales/en.ts b/src/locales/en.ts
index ed859725..42a9b56f 100644
--- a/src/locales/en.ts
+++ b/src/locales/en.ts
@@ -4722,5 +4722,39 @@ export default {
warningNoPlanData: 'No plan data to save',
saveSuccess: 'Schedule saved successfully'
}
+ },
+ EnergyOverview: {
+ filters: {
+ org: 'Region',
+ orgPlaceholder: 'Please select region',
+ energyType: 'Energy Type',
+ energyTypePlaceholder: 'Please select energy type',
+ timeRange: 'Time Range'
+ },
+ panels: {
+ trend: 'Energy Usage Trend',
+ region: 'Regional Energy Share',
+ top5: 'Top 5 Energy Consumers',
+ detail: 'Energy Details'
+ },
+ table: {
+ rank: 'Rank',
+ name: 'Name',
+ region: 'Region',
+ usage: 'Usage',
+ meterName: 'Meter Name',
+ energyType: 'Energy Type',
+ energyUsage: 'Energy Usage',
+ startTime: 'Start Time',
+ endTime: 'End Time'
+ },
+ chart: {
+ usage: 'Usage',
+ time: 'Time',
+ regionEnergy: 'Regional Energy',
+ totalUsage: 'Total Usage'
+ },
+ empty: 'Please configure energy types first',
+ exportSuccess: 'Export started'
}
}
diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts
index 0d226c27..36f12d80 100644
--- a/src/locales/zh-CN.ts
+++ b/src/locales/zh-CN.ts
@@ -4933,5 +4933,39 @@ export default {
warningNoPlanData: '暂无可保存的计划数据',
saveSuccess: '排产计划保存成功'
}
+ },
+ EnergyOverview: {
+ filters: {
+ org: '所属区域',
+ orgPlaceholder: '请选择所属区域',
+ energyType: '能源类型',
+ energyTypePlaceholder: '请选择能源类型',
+ timeRange: '时间范围'
+ },
+ panels: {
+ trend: '能源用量趋势',
+ region: '区域能耗占比',
+ top5: '能耗排行 TOP5',
+ detail: '能源明细表'
+ },
+ table: {
+ rank: '排名',
+ name: '名称',
+ region: '所属区域',
+ usage: '用量',
+ meterName: '表名称',
+ energyType: '能源类型',
+ energyUsage: '能源用量',
+ startTime: '开始时间',
+ endTime: '结束时间'
+ },
+ chart: {
+ usage: '用量',
+ time: '时间',
+ regionEnergy: '区域能耗',
+ totalUsage: '总用量'
+ },
+ empty: '请先配置能源类型',
+ exportSuccess: '导出已发起'
}
}
diff --git a/src/views/mes/energyOverview/index.vue b/src/views/mes/energyOverview/index.vue
index a674c335..e96bd42f 100644
--- a/src/views/mes/energyOverview/index.vue
+++ b/src/views/mes/energyOverview/index.vue
@@ -8,35 +8,35 @@
:inline="true"
label-width="auto"
>
-
+
-
+
-
+
- 查询
+ {{ t('common.query') }}
- 重置
+ {{ t('common.reset') }}
- 导出
+ {{ t('action.export') }}
@@ -88,7 +88,7 @@
@@ -99,7 +99,7 @@
@@ -113,19 +113,24 @@
-
+
{{ scope.$index + 1 }}
-
-
-
+
+
+
@@ -133,17 +138,22 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
+
@@ -173,7 +183,7 @@ import {
EnergyOverviewRankVO,
EnergyOverviewRespVO
} from '@/api/mes/energydevice'
-import {OrganizationApi, OrganizationVO} from "@/api/mes/organization";
+import { OrganizationApi, OrganizationVO } from '@/api/mes/organization'
defineOptions({ name: 'EnergyOverview' })
@@ -192,6 +202,7 @@ interface MetricCard {
type DetailRow = EnergyOverviewDetailVO
+const { t } = useI18n()
const message = useMessage()
const defaultTimeRange = ['2026-05-04 00:00:00', '2026-05-05 23:59:59']
@@ -230,12 +241,12 @@ const trendChartOptions = reactive({
trigger: 'axis',
formatter: (params: any) => {
const item = params?.[0]
- return `${item?.axisValue || ''}
用量:${item?.data || 0} ${selectedEnergyUnit.value}`
+ return `${item?.axisValue || ''}
${t('EnergyOverview.chart.usage')}:${item?.data || 0} ${selectedEnergyUnit.value}`
}
},
legend: {
top: 4,
- data: ['用量']
+ data: [t('EnergyOverview.chart.usage')]
},
grid: {
left: 24,
@@ -247,7 +258,7 @@ const trendChartOptions = reactive({
xAxis: {
type: 'category',
boundaryGap: false,
- name: '时间',
+ name: t('EnergyOverview.chart.time'),
nameLocation: 'middle',
nameGap: 28,
data: trendXAxis.value,
@@ -263,7 +274,7 @@ const trendChartOptions = reactive({
},
series: [
{
- name: '用量',
+ name: t('EnergyOverview.chart.usage'),
type: 'line',
smooth: true,
symbol: 'circle',
@@ -308,7 +319,7 @@ const regionPieOptions = reactive({
},
series: [
{
- name: '区域能耗',
+ name: t('EnergyOverview.chart.regionEnergy'),
type: 'pie',
radius: ['58%', '76%'],
center: ['34%', '50%'],
@@ -316,7 +327,7 @@ const regionPieOptions = reactive({
label: {
show: true,
position: 'center',
- formatter: `总用量\n{total|${regionTotal.value} ${selectedEnergyUnit.value}}`,
+ formatter: `${t('EnergyOverview.chart.totalUsage')}\n{total|${regionTotal.value} ${selectedEnergyUnit.value}}`,
color: '#303133',
rich: {
total: {
@@ -368,20 +379,26 @@ const updateCharts = (data: EnergyOverviewRespVO) => {
trendChartOptions.xAxis = {
...(trendChartOptions.xAxis as any),
- data: trendXAxis.value
+ data: trendXAxis.value,
+ name: t('EnergyOverview.chart.time')
}
trendChartOptions.yAxis = {
...(trendChartOptions.yAxis as any),
name: selectedEnergyUnit.value
}
+ if (Array.isArray(trendChartOptions.legend?.data)) {
+ trendChartOptions.legend.data = [t('EnergyOverview.chart.usage')]
+ }
if (Array.isArray(trendChartOptions.series) && trendChartOptions.series[0]) {
+ ;(trendChartOptions.series[0] as any).name = t('EnergyOverview.chart.usage')
;(trendChartOptions.series[0] as any).data = trendSeries.value
}
if (Array.isArray(regionPieOptions.series) && regionPieOptions.series[0]) {
+ ;(regionPieOptions.series[0] as any).name = t('EnergyOverview.chart.regionEnergy')
;(regionPieOptions.series[0] as any).data = regionItems.value
;(regionPieOptions.series[0] as any).label = {
...(regionPieOptions.series[0] as any).label,
- formatter: `总用量\n{total|${regionTotal.value} ${selectedEnergyUnit.value}}`
+ formatter: `${t('EnergyOverview.chart.totalUsage')}\n{total|${regionTotal.value} ${selectedEnergyUnit.value}}`
}
}
}
@@ -463,7 +480,7 @@ const handleExport = async () => {
startTime: timeRange[0],
endTime: timeRange[1]
})
- message.success('导出已发起')
+ message.success(t('EnergyOverview.exportSuccess'))
}
const loadOrgOptions = async () => {
@@ -475,7 +492,6 @@ const loadOrgOptions = async () => {
.map((r) => ({ label: r.name, value: r.id, raw: r }))
}
-
onMounted(async () => {
await loadOrgOptions()
await getEnergyTypes()
From db1e813950d9f5d304bc76b2ce78e357487509a3 Mon Sep 17 00:00:00 2001
From: liutao <790864623@qq.com>
Date: Mon, 18 May 2026 08:07:44 +0800
Subject: [PATCH 3/3] =?UTF-8?q?=E6=97=B6=E9=97=B4=E9=99=90=E5=88=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/locales/en.ts | 3 +
src/locales/zh-CN.ts | 3 +
src/views/mes/energyOverview/index.vue | 113 +++++++++++++++++++++++--
3 files changed, 113 insertions(+), 6 deletions(-)
diff --git a/src/locales/en.ts b/src/locales/en.ts
index 42a9b56f..17c11117 100644
--- a/src/locales/en.ts
+++ b/src/locales/en.ts
@@ -4724,6 +4724,9 @@ export default {
}
},
EnergyOverview: {
+ messages: {
+ singleDayOnly: 'The time range can only query data within a single day'
+ },
filters: {
org: 'Region',
orgPlaceholder: 'Please select region',
diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts
index 36f12d80..5ca068dc 100644
--- a/src/locales/zh-CN.ts
+++ b/src/locales/zh-CN.ts
@@ -4935,6 +4935,9 @@ export default {
}
},
EnergyOverview: {
+ messages: {
+ singleDayOnly: '时间范围只能查询同一天的数据'
+ },
filters: {
org: '所属区域',
orgPlaceholder: '请选择所属区域',
diff --git a/src/views/mes/energyOverview/index.vue b/src/views/mes/energyOverview/index.vue
index e96bd42f..f525cba0 100644
--- a/src/views/mes/energyOverview/index.vue
+++ b/src/views/mes/energyOverview/index.vue
@@ -205,7 +205,34 @@ type DetailRow = EnergyOverviewDetailVO
const { t } = useI18n()
const message = useMessage()
-const defaultTimeRange = ['2026-05-04 00:00:00', '2026-05-05 23:59:59']
+const getTodayTimeRange = () => {
+ const now = new Date()
+ const year = now.getFullYear()
+ const month = String(now.getMonth() + 1).padStart(2, '0')
+ const day = String(now.getDate()).padStart(2, '0')
+ const date = `${year}-${month}-${day}`
+ return [`${date} 00:00:00`, `${date} 23:59:59`]
+}
+
+const parseRangeTime = (value?: string) => {
+ if (!value) return undefined
+ const date = new Date(value.replace(/-/g, '/'))
+ return Number.isNaN(date.getTime()) ? undefined : date
+}
+
+const isSingleDayRange = (timeRange?: string[]) => {
+ if (!timeRange || timeRange.length !== 2) return false
+ const start = parseRangeTime(timeRange[0])
+ const end = parseRangeTime(timeRange[1])
+ if (!start || !end) return false
+ return (
+ start.getFullYear() === end.getFullYear() &&
+ start.getMonth() === end.getMonth() &&
+ start.getDate() === end.getDate()
+ )
+}
+
+const defaultTimeRange = getTodayTimeRange()
const orgOptions = ref<{ label: string; value: string | number; raw?: OrganizationVO }[]>([])
const loading = ref(false)
@@ -352,6 +379,47 @@ const metricThemeMap: Record = {
range: { icon: 'ep:calendar', theme: 'orange' }
}
+const buildFallbackTrendXAxis = () => {
+ const timeRange = queryParams.timeRange?.length === 2 ? queryParams.timeRange : defaultTimeRange
+ const [startTime, endTime] = timeRange
+ const start = new Date(startTime.replace(/-/g, '/'))
+ const end = new Date(endTime.replace(/-/g, '/'))
+ if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime()) || start > end) {
+ return []
+ }
+
+ const sameDay =
+ start.getFullYear() === end.getFullYear() &&
+ start.getMonth() === end.getMonth() &&
+ start.getDate() === end.getDate()
+
+ const axis: string[] = []
+ if (sameDay) {
+ const current = new Date(start)
+ current.setMinutes(0, 0, 0)
+ const limit = new Date(end)
+ limit.setMinutes(0, 0, 0)
+ while (current <= limit) {
+ axis.push(`${String(current.getHours()).padStart(2, '0')}:00`)
+ current.setHours(current.getHours() + 1)
+ }
+ return axis
+ }
+
+ const current = new Date(start)
+ current.setHours(0, 0, 0, 0)
+ const limit = new Date(end)
+ limit.setHours(0, 0, 0, 0)
+ while (current <= limit) {
+ const year = current.getFullYear()
+ const month = String(current.getMonth() + 1).padStart(2, '0')
+ const day = String(current.getDate()).padStart(2, '0')
+ axis.push(`${year}-${month}-${day}`)
+ current.setDate(current.getDate() + 1)
+ }
+ return axis
+}
+
const normalizeMetricCards = (metrics: EnergyOverviewMetricVO[]) => {
metricCards.value = metrics.map((item) => ({
key: item.key,
@@ -368,8 +436,13 @@ const normalizeMetricCards = (metrics: EnergyOverviewMetricVO[]) => {
}
const updateCharts = (data: EnergyOverviewRespVO) => {
- trendXAxis.value = data.trendChart?.xAxis || []
- trendSeries.value = (data.trendChart?.data || []).map((item) => Number(item) || 0)
+ const fallbackXAxis = buildFallbackTrendXAxis()
+ trendXAxis.value = data.trendChart?.xAxis?.length ? data.trendChart.xAxis : fallbackXAxis
+ const responseSeries = (data.trendChart?.data || []).map((item) => Number(item) || 0)
+ trendSeries.value =
+ responseSeries.length > 0
+ ? responseSeries
+ : new Array(trendXAxis.value.length).fill(0)
regionItems.value = (data.regionChart?.items || []).map((item) => ({
name: item.name,
value: Number(item.value) || 0,
@@ -449,18 +522,31 @@ const getDefaultEnergyType = (list: EnergyTypeVO[]) => list[0]
const getEnergyTypes = async () => {
try {
- const data = await EnergyTypeApi.getEnergyTypeList()
+ const data = await EnergyTypeApi.getEnergyTypeList({ orgId: queryParams.orgId })
energyTypeOptions.value = normalizeEnergyTypeList(data)
} catch (error) {
energyTypeOptions.value = []
}
- const defaultEnergyType = getDefaultEnergyType(energyTypeOptions.value)
+ let defaultEnergyType = getDefaultEnergyType(energyTypeOptions.value)
+ try {
+ const deviceRes = await EnergyDeviceApi.getList({ orgId: queryParams.orgId })
+ const devices = ((deviceRes as any)?.data || deviceRes || []) as Array<{ deviceTypeId?: number }>
+ const deviceTypeIds = new Set(devices.map((item) => item.deviceTypeId).filter(Boolean))
+ defaultEnergyType =
+ energyTypeOptions.value.find((item) => deviceTypeIds.has(item.id)) || defaultEnergyType
+ } catch (error) {
+ // ignore and use the first energy type
+ }
defaultEnergyTypeId.value = defaultEnergyType?.id
queryParams.energyTypeId = defaultEnergyType?.id
}
const handleQuery = () => {
+ if (!isSingleDayRange(queryParams.timeRange)) {
+ message.warning(t('EnergyOverview.messages.singleDayOnly'))
+ return
+ }
queryParams.pageNo = 1
getList()
}
@@ -469,11 +555,15 @@ const resetQuery = () => {
queryFormRef.value?.resetFields()
queryParams.orgId = undefined
queryParams.energyTypeId = defaultEnergyTypeId.value
- queryParams.timeRange = [...defaultTimeRange]
+ queryParams.timeRange = getTodayTimeRange()
handleQuery()
}
const handleExport = async () => {
+ if (!isSingleDayRange(queryParams.timeRange)) {
+ message.warning(t('EnergyOverview.messages.singleDayOnly'))
+ return
+ }
const timeRange = queryParams.timeRange?.length === 2 ? queryParams.timeRange : defaultTimeRange
await EnergyDeviceApi.exportQueryDataRecords({
orgId: queryParams.orgId,
@@ -499,6 +589,17 @@ onMounted(async () => {
getList()
}
})
+
+watch(
+ () => queryParams.orgId,
+ async () => {
+ await getEnergyTypes()
+ queryParams.pageNo = 1
+ if (hasEnergyTypes.value) {
+ getList()
+ }
+ }
+)