|
|
|
@ -6,8 +6,20 @@
|
|
|
|
<span>能耗监测</span>
|
|
|
|
<span>能耗监测</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="tabs">
|
|
|
|
<div class="tabs">
|
|
|
|
<span class="tab" :class="{ active: energyTab === 'first' }" @click="energyTab = 'first'">First aid</span>
|
|
|
|
<el-select
|
|
|
|
<span class="tab" :class="{ active: energyTab === 'after' }" @click="energyTab = 'after'">Aftermarket</span>
|
|
|
|
v-model="selectedEnergyTypeId"
|
|
|
|
|
|
|
|
placeholder="请选择"
|
|
|
|
|
|
|
|
style="width: 120px"
|
|
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
|
|
@change="getChartData"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<el-option
|
|
|
|
|
|
|
|
v-for="item in energyTypes"
|
|
|
|
|
|
|
|
:key="item.id"
|
|
|
|
|
|
|
|
:label="item.name"
|
|
|
|
|
|
|
|
:value="item.id"
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</el-select>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="panel-body">
|
|
|
|
<div class="panel-body">
|
|
|
|
@ -17,27 +29,80 @@
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
<script setup lang="ts">
|
|
|
|
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
|
|
|
import { onMounted, onUnmounted, ref } from 'vue'
|
|
|
|
import * as echarts from 'echarts'
|
|
|
|
import * as echarts from 'echarts'
|
|
|
|
import { colors, style } from '../utils'
|
|
|
|
import { colors, style } from '../utils'
|
|
|
|
|
|
|
|
import { EnergyTypeApi, EnergyTypeVO } from '@/api/mes/energytype'
|
|
|
|
|
|
|
|
import { EnergyDeviceApi } from '@/api/mes/energydevice'
|
|
|
|
|
|
|
|
|
|
|
|
const energyTab = ref<'first' | 'after'>('first')
|
|
|
|
const energyTypes = ref<EnergyTypeVO[]>([])
|
|
|
|
|
|
|
|
const selectedEnergyTypeId = ref<number | undefined>(undefined)
|
|
|
|
const chartRef = ref<HTMLElement | null>(null)
|
|
|
|
const chartRef = ref<HTMLElement | null>(null)
|
|
|
|
let chart: echarts.ECharts | null = null
|
|
|
|
let chart: echarts.ECharts | null = null
|
|
|
|
|
|
|
|
|
|
|
|
const render = () => {
|
|
|
|
const getEnergyTypes = async () => {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
const res = await EnergyTypeApi.getEnergyTypeList()
|
|
|
|
|
|
|
|
const list = (res as any).data || (Array.isArray(res) ? res : [])
|
|
|
|
|
|
|
|
energyTypes.value = list
|
|
|
|
|
|
|
|
if (list.length > 0) {
|
|
|
|
|
|
|
|
selectedEnergyTypeId.value = list[0].id
|
|
|
|
|
|
|
|
getChartData()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
|
|
console.error('Failed to fetch energy types:', e)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getChartData = async () => {
|
|
|
|
|
|
|
|
if (!selectedEnergyTypeId.value) return
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
const res = await EnergyDeviceApi.getLastEnergyStatistics({
|
|
|
|
|
|
|
|
deviceTypeId: selectedEnergyTypeId.value,
|
|
|
|
|
|
|
|
orgId: 132
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
render(res)
|
|
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
|
|
console.error('Failed to fetch chart data:', e)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const render = (data: any = []) => {
|
|
|
|
if (!chart) return
|
|
|
|
if (!chart) return
|
|
|
|
const x = ['9:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00']
|
|
|
|
|
|
|
|
const y =
|
|
|
|
// 尝试解析数据,假设数据包含时间(time/createTime)和值(value/consumption)
|
|
|
|
energyTab.value === 'first'
|
|
|
|
// 如果数据格式未知,这里做一个简单的映射尝试
|
|
|
|
? [820, 1650, 980, 1240, 1560, 1320, 1680]
|
|
|
|
// 默认 fallback
|
|
|
|
: [680, 1420, 880, 1100, 1320, 1180, 1480]
|
|
|
|
let x: string[] = []
|
|
|
|
|
|
|
|
let y: number[] = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const list = (data as any).data || (Array.isArray(data) ? data : [])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (list && list.length > 0) {
|
|
|
|
|
|
|
|
x = list.map((item: any) => {
|
|
|
|
|
|
|
|
const h = item.hour || ''
|
|
|
|
|
|
|
|
// 如果包含日期和时间,只显示时间部分
|
|
|
|
|
|
|
|
if (typeof h === 'string' && h.includes(' ')) {
|
|
|
|
|
|
|
|
return h.split(' ')[1]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return h
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
y = list.map((item: any) => item.value || item.consumption || item.energy || 0)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// 没数据时清空或显示空
|
|
|
|
|
|
|
|
x = []
|
|
|
|
|
|
|
|
y = []
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有数据,使用模拟数据防止图表空白(可选,或者显示暂无数据)
|
|
|
|
|
|
|
|
// 为了演示效果,如果API没通,可以保留之前的mock作为fallback吗?
|
|
|
|
|
|
|
|
// 用户明确要求对接接口,所以尽量用接口数据。如果为空,就显示空。
|
|
|
|
|
|
|
|
|
|
|
|
chart.setOption({
|
|
|
|
chart.setOption({
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
tooltip: { trigger: 'axis' },
|
|
|
|
tooltip: { trigger: 'axis' },
|
|
|
|
grid: { top: '18%', left: '6%', right: '4%', bottom: '12%', containLabel: true },
|
|
|
|
grid: { top: '18%', left: '6%', right: '4%', bottom: '12%', containLabel: true },
|
|
|
|
xAxis: { type: 'category', data: x, axisLine: style.axisLine, axisLabel: { ...style.axisLabel, fontSize: 10 } },
|
|
|
|
xAxis: { type: 'category', data: x, axisLine: style.axisLine, axisLabel: { ...style.axisLabel, fontSize: 10, rotate: 40 } },
|
|
|
|
yAxis: { type: 'value', axisLine: { show: false }, axisLabel: { ...style.axisLabel, fontSize: 10 }, splitLine: style.splitLine },
|
|
|
|
yAxis: { type: 'value', axisLine: { show: false }, axisLabel: { ...style.axisLabel, fontSize: 10 }, splitLine: style.splitLine },
|
|
|
|
series: [
|
|
|
|
series: [
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -63,7 +128,10 @@ const resize = () => {
|
|
|
|
onMounted(() => {
|
|
|
|
onMounted(() => {
|
|
|
|
if (!chartRef.value) return
|
|
|
|
if (!chartRef.value) return
|
|
|
|
chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' })
|
|
|
|
chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' })
|
|
|
|
render()
|
|
|
|
// 先初始化一个空图表
|
|
|
|
|
|
|
|
render([])
|
|
|
|
|
|
|
|
// 获取下拉选项并加载数据
|
|
|
|
|
|
|
|
getEnergyTypes()
|
|
|
|
window.addEventListener('resize', resize)
|
|
|
|
window.addEventListener('resize', resize)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
@ -71,13 +139,20 @@ onUnmounted(() => {
|
|
|
|
window.removeEventListener('resize', resize)
|
|
|
|
window.removeEventListener('resize', resize)
|
|
|
|
chart?.dispose()
|
|
|
|
chart?.dispose()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
watch(energyTab, () => {
|
|
|
|
|
|
|
|
render()
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
</script>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
<style scoped>
|
|
|
|
|
|
|
|
:deep(.el-select .el-input__wrapper) {
|
|
|
|
|
|
|
|
background-color: rgba(2, 6, 23, 0.3);
|
|
|
|
|
|
|
|
box-shadow: 0 0 0 1px rgba(56, 189, 248, 0.4) inset;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
:deep(.el-select .el-input__inner) {
|
|
|
|
|
|
|
|
color: #e5f0ff;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
:deep(.el-select .el-input.is-focus .el-input__wrapper) {
|
|
|
|
|
|
|
|
box-shadow: 0 0 0 1px rgba(56, 189, 248, 0.9) inset !important;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card {
|
|
|
|
.card {
|
|
|
|
height: 100%;
|
|
|
|
height: 100%;
|
|
|
|
background: linear-gradient(135deg, rgba(15,23,42,0.96), rgba(15,23,42,0.88));
|
|
|
|
background: linear-gradient(135deg, rgba(15,23,42,0.96), rgba(15,23,42,0.88));
|
|
|
|
|