Files
energy_storage/web/src/components/monitor/device.vue

518 lines
12 KiB
Vue
Raw Normal View History

<template>
<div class="device" ref="device">
<div class="device-item" v-for="item in deviceList" :key="item">
<div class="item-header">
<div style="display: flex; width: 50%">
<div class="icon-bg">
<span class="iconfont" :class="getIcongont(item)"></span>
</div>
<div class="title">
<span class="number">{{ item.device_id }}</span>
<span class="name">{{ item.name }}</span>
<span class="number type">{{ item.typename }}</span>
</div>
</div>
<div class="status">
<div class="status-item">
<span>{{ ['离线', '在线'][item.is_online] }}</span>
<span class="text">在线状态</span>
</div>
<div class="status-item">
<span>{{ ['正常', '错误'][item.is_error] }}</span>
<span class="text">故障状态</span>
</div>
<div class="status-item">
<span>{{ ['空闲', '工作'][item.is_running] }}</span>
<span class="text">工作状态</span>
</div>
</div>
</div>
<div class="item-content">
<div v-for="info in item.params" :key="info.k" class="item-info">
<span class="text">{{ info.k }}</span>
<span class="value">{{ info.v }}</span>
</div>
</div>
<div class="item-button">
<div v-if="item.view == 1">
<span class="text">实时数据</span>
<a-button type="primary" size="small" @click="openModal(item, 1)">查看</a-button>
</div>
<div v-if="item.type == 105">
<span class="text">单体信息</span>
<a-button type="primary" size="small" @click="openModal(item, 2)">查看</a-button>
</div>
</div>
</div>
<a-modal
v-model:open="modalOpen"
@ok="handleOk"
2025-09-11 16:14:55 +08:00
width="60%"
class="modal-device"
:get-container="() => $refs.device"
>
2025-09-11 16:14:55 +08:00
<div v-if="modalComponent == 1" class="modal-content">
<div class="item">
<div class="title">
2025-09-11 16:14:55 +08:00
电流电压
<!-- <div>电流电压</div>
<img src="@/assets/images/titleLine.png" alt="" /> -->
</div>
<div class="echarts">
<predictEcharts
:chart-options="chartOptions[0]"
:chart-data="chartData"
ref="chartRef1"
/>
</div>
</div>
2025-09-11 16:14:55 +08:00
<div class="item">
<div class="title">功率</div>
<div class="echarts">
<predictEcharts
:chart-options="chartOptions[1]"
:chart-data="chartData"
ref="chartRef2"
/>
</div>
</div>
</div>
<div class="content-table" style="height: 600px" v-else>
<a-table
:columns="columns"
:data-source="tableData"
size="small"
:scroll="{ y: 500 }"
:pagination="false"
row-class-name="no-hover-row"
row-key="id"
>
</a-table>
</div>
</a-modal>
</div>
</template>
<script>
import predictEcharts from '@/components/predict/predictEcharts.vue'
import { postReq, getReq } from '@/request/api'
import { deviceTypeList } from '@/utils/config'
export default {
name: '',
components: { predictEcharts },
props: {
stationId: {
type: String,
default: ''
},
systemType: {
type: Number,
default: 1
}
},
data() {
return {
modalOpen: false,
deviceList: [],
chartOptions: [
{
type: 'line',
smooth: true,
dataKey: 'chargeDischarge',
infoKeys: [
{
key: 'V',
label: '电压',
seriesOptions: {
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#00FDF9' // 充电电量线条颜色
},
lineStyle: {
color: '#00FDF9' // 充电电量线条颜色
}
}
},
{
key: 'I',
label: '电流',
seriesOptions: {
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#3E7EEF' // 充电电量线条颜色
},
lineStyle: {
color: '#3E7EEF' // 充电电量线条颜色
}
}
}
]
},
{
type: 'line',
smooth: true,
dataKey: 'chargeDischarge',
infoKeys: [
{
key: 'P',
label: '功率',
seriesOptions: {
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#00FDF9' // 充电电量线条颜色
},
lineStyle: {
color: '#00FDF9' // 充电电量线条颜色
}
}
}
]
}
],
chartData: {
xdata: [],
ydata: {}
},
modalComponent: 1,
columns: [
{
title: '序号',
dataIndex: 'id',
key: 'id',
ellipsis: true,
fixed: 'left'
},
{
title: '单体SOC%',
dataIndex: 'SOC',
key: 'SOC'
},
{
title: '单体SOH%',
dataIndex: 'SOH',
key: 'SOH'
},
{
title: '单体电压V',
dataIndex: 'V',
key: 'V'
},
{
title: '单体温度(℃)',
dataIndex: 'T',
key: 'T'
},
{
title: '单体内阻(Ω)',
dataIndex: 'R_i',
key: 'R_i'
}
],
tableData: [],
pageOption: {
// pageSize: 1000,
// page: 1
},
tableOption: {
scroll: {
y: 500
},
page: false
}
}
},
watch: {
// 监听父组件数据变化
stationId(newVal) {
if (newVal) {
this.getDeviceList()
}
},
systemType(newVal, oldVal) {
if (newVal !== oldVal) {
this.getDeviceList()
}
}
},
mounted() {
this.getDeviceList()
2025-09-11 16:14:55 +08:00
},
methods: {
handlePagesizeChange(pageOption) {
this.pageOption.pageSize = pageOption.pageSize
this.pageOption.page = pageOption.page
this.getList()
},
getIcongont(ele) {
return deviceTypeList.find((item) => item.value == ele.type).iconfont || ''
},
generateTimePoints() {
const timePoints = []
for (let hour = 0; hour <= 24; hour++) {
for (let minute = 0; minute < 60; minute += 10) {
// 处理24:00的特殊情况
if (hour === 24 && minute === 0) {
timePoints.push('24:00')
break
}
// 格式化小时和分钟,确保两位数
const formattedHour = hour.toString().padStart(2, '0')
const formattedMinute = minute.toString().padStart(2, '0')
timePoints.push(`${formattedHour}:${formattedMinute}`)
}
}
return timePoints
},
//查看实时数据
async getDevicCharts(item) {
try {
const res = await getReq('/queryDevicCharts', {
station_id: this.stationId,
device_id: item.device_id
})
this.chartData.ydata = res.data
this.chartData.xdata = this.generateTimePoints()
2025-09-11 16:14:55 +08:00
this.$nextTick(() => {
if (this.$refs.chartRef1) {
this.$refs.chartRef1.initCharts()
}
if (this.$refs.chartRef2) {
this.$refs.chartRef2.initCharts()
}
})
// this.$refs.chartRef1.initCharts()
// this.$refs.chartRef2.initCharts()
} catch (error) {
console.log(error)
}
},
//查询BCU单体信息
async getDeviceBCUDetail(item) {
try {
const res = await getReq('/queryDeviceBCUDetail', {
station_id: this.stationId,
device_id: item.device_id
})
this.tableData = res.data.map((item, index) => {
item.id = index + 1
return item
})
} catch (error) {
console.log(error)
}
},
//请求运行监控系统设备信息
async getDeviceList() {
try {
const res = await getReq('/queryDevicByCategory', {
station_id: this.stationId,
category: this.systemType
})
this.deviceList = res.data
} catch (error) {
this.deviceList = []
console.log(error)
}
},
async openModal(item, val) {
console.log(item, '=============')
this.modalComponent = val
2025-09-11 16:14:55 +08:00
this.modalOpen = true
if (val == 1) {
await this.getDevicCharts(item)
} else {
await this.getDeviceBCUDetail(item)
}
},
handleOk() {
this.modalOpen = false
}
}
}
</script>
<style lang="scss" scoped>
.device {
width: 100%;
height: 100%;
margin-left: 20px;
2025-09-11 16:14:55 +08:00
display: flex;
flex-wrap: wrap;
grid-gap: 20px;
overflow-y: auto;
2025-09-11 16:14:55 +08:00
align-content: flex-start;
// grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
.device-item {
border-radius: 15px;
background: $bg2-color;
padding: 15px;
min-width: 340px;
max-width: 430px;
2025-09-11 16:14:55 +08:00
height: 260px;
flex: 1;
.item-header {
display: flex;
align-items: center;
height: 70px;
color: #fff;
justify-content: space-between;
.icon-bg {
width: 66px;
height: 66px;
text-align: center;
line-height: 66px;
border-radius: 6px;
background: linear-gradient(90deg, #3dfefa 0%, #2a82e4 2.96%, #27a188 100%),
linear-gradient(90deg, #3dfefa 0%, #01dfef 2.96%, #08a5ff 100%);
.iconfont {
font-size: 45px;
}
}
.title {
display: flex;
flex-direction: column;
justify-content: space-around;
margin-left: 15px;
}
.number {
font-size: 12px;
}
.name {
font-size: 14px;
}
.type {
color: #08a5ff;
}
.status {
display: flex;
font-size: 14px;
height: 100%;
width: 50%;
justify-content: space-between;
&-item {
display: flex;
flex-direction: column;
text-align: center;
justify-content: space-evenly;
span:first-child {
font-weight: 700;
}
.text {
color: $text-color;
}
}
}
}
.item-content {
grid-template-columns: 1fr 1fr;
color: #fff;
display: grid;
margin-top: 15px;
margin-bottom: 3px;
padding: 0 10px;
height: 120px;
overflow-y: auto;
.value {
font-weight: 700;
}
.item-info {
height: 30px;
}
}
.item-button {
width: 100%;
padding-left: 10px;
display: flex;
div {
width: calc(50% - 10px);
}
}
.text {
color: $text-color;
}
.video {
margin-top: 10px;
}
}
.content-table {
height: 700px;
margin-top: 40px;
:deep(.ant-table-header tr th) {
background: $table-border !important;
color: #fff;
}
:deep(.ant-table-body tr td, .ant-table-cell) {
background: $table-bg !important;
color: #fff;
}
}
}
.environment {
width: 200px;
}
2025-09-11 16:14:55 +08:00
.modal-device {
color: #fff;
.modal-content {
height: 700px;
.item {
// height: 300px;
.title {
color: #fff;
width: 230px;
border-bottom: 5px solid transparent;
border-image: url('@/assets/boxBottom.png') 0 0 100% 0 stretch;
}
.echarts {
height: 300px;
}
}
}
}
:deep(.ant-modal-body) {
:deep(.ant-table-wrapper .ant-table-row-expand-icon) {
color: $green !important;
}
//表格行悬浮样式
.no-hover-row:hover > td {
// background-color: transparent !important;
background-color: #f0f8ff !important;
}
}
2025-09-11 16:14:55 +08:00
:deep(.ant-table-cell) {
&::before {
width: 0 !important;
}
}
:deep(.ant-table-thead > tr > td) {
border-bottom: none !important;
border-top: none !important;
}
:deep(.ant-table-wrapper .ant-table-tbody > tr > td) {
border-top: none !important;
}
:deep(.ant-table-wrapper .ant-table-thead > tr > th) {
border-bottom: none !important;
}
</style>