|
|
|
|
@ -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<string, { icon: string; theme: string }> = {
|
|
|
|
|
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()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|