feat(web): 新增设备管理功能

- 新增设备管理页面和相关功能
This commit is contained in:
zhoumengru
2025-09-09 09:39:15 +08:00
36 changed files with 4123 additions and 815 deletions

View File

@@ -1,58 +1,89 @@
<template>
<div class="device">
<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"></div>
<div class="icon-bg">
<span class="iconfont" :class="getIcongont(item)"></span>
</div>
<div class="title">
<span class="number">521245786665412</span>
<span class="name">逆变器1</span>
<span class="number type">逆变器</span>
<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>在线</span>
<span>{{ ['离线', '在线'][item.is_online] }}</span>
<span class="text">在线状态</span>
</div>
<div class="status-item">
<span>在线</span>
<span>{{ ['正常', '错误'][item.is_error] }}</span>
<span class="text">故障状态</span>
</div>
<div class="status-item">
<span>在线</span>
<span>{{ ['空闲', '工作'][item.is_running] }}</span>
<span class="text">工作状态</span>
</div>
</div>
</div>
<div class="item-content">
<div v-for="info in chunengInfo" :key="info.key">
<span class="text">{{ info.label }}</span>
<a-button
v-if="info.key === 'realTimeData'"
type="primary"
size="small"
@click="openModal"
>查看</a-button
>
<span v-else class="value">{{ info.value }}</span>
<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 v-if="item.view == 1" class="item-button">
<span class="text">实时数据</span>
<a-button type="primary" size="small" @click="openModal(item)">查看</a-button>
</div>
</div>
<a-modal v-model:open="modalOpen" @ok="handleOk" width="800px">
<!-- <p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p> -->
<a-modal
v-model:open="modalOpen"
@ok="handleOk"
width="90%"
class="modal-device"
:get-container="() => $refs.device"
>
<div>
<div class="title">
<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>
<div>
<div class="title">
<div>功率</div>
<img src="@/assets/images/titleLine.png" alt="" />
</div>
<div class="echarts">
<predictEcharts
:chart-options="chartOptions[1]"
:chart-data="chartData"
ref="chartRef2"
/>
</div>
</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: {},
components: { predictEcharts },
props: {
stationId: {
type: String,
@@ -79,7 +110,70 @@ export default {
{ label: '实时数据', key: 'realTimeData', value: '0.01kWh' },
{ label: '额定功率', key: 'ratedPower', value: '0.01kW' },
{ label: '冷却方式', key: 'coolingMethod', value: '风冷' }
]
],
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: {}
}
}
},
watch: {
@@ -99,24 +193,65 @@ export default {
this.getDeviceList()
},
methods: {
async getDeviceList() {
const data = {
category: this.systemType,
'station_id': this.stationId,
page: 0,
'page_size': 1000
}
try {
const res = await getReq('/queryDeviceList', data)
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()
this.$refs.chartRef1.initCharts()
this.$refs.chartRef2.initCharts()
console.log(res)
this.deviceList = res.data
// this.selectStation=this.stations[0]['station_id']
} catch (error) {
console.log(error)
}
},
openModal() {
//请求运行监控系统设备信息
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) {
await this.getDevicCharts(item)
this.modalOpen = true
},
handleOk() {
@@ -136,8 +271,6 @@ export default {
grid-template-columns: 1fr 1fr 1fr;
overflow-y: auto;
.device-item {
// width: 410px;
// height: 340px;
border-radius: 15px;
background: $bg2-color;
@@ -149,11 +282,16 @@ export default {
color: #fff;
justify-content: space-between;
.icon-bg {
width: 76px;
height: 72px;
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: 50px;
}
}
.title {
display: flex;
@@ -194,12 +332,20 @@ export default {
grid-template-columns: 1fr 1fr;
color: #fff;
display: grid;
line-height: 45px;
// line-height: 45px;
margin-top: 15px;
padding: 0 10px;
height: 120px;
overflow-y: auto;
.value {
font-weight: 700;
}
.item-info {
height: 30px;
}
}
.item-button {
padding-left: 10px;
}
.text {
color: $text-color;
@@ -212,4 +358,22 @@ export default {
.environment {
width: 200px;
}
:deep(.modal-device) {
color: #fff;
.title {
display: flex;
font-weight: 700;
flex-direction: column;
img {
width: 232px;
height: 6px;
margin-top: 10px;
}
}
.echarts {
width: 100%;
height: 280px;
}
}
</style>

View File

@@ -32,13 +32,12 @@
</div>
<div class="table-content">
<ComTable
:columns="columns"
:table-data="tableData"
:columns="columns[activeTab]"
:table-data="tableDatas[activeTab]"
@handlePagesizeChange="handlePagesizeChange"
ref="comTable"
:table-option="tableOption"
:page-option="pageOption"
:table-h="tableH"
>
</ComTable>
</div>
@@ -46,65 +45,143 @@
</template>
<script>
import { postReq, getReq } from '@/request/api'
export default {
name: '',
components: {},
props: {},
props: {
stationId: {
type: String,
default: ''
},
systemType: {
type: Number,
default: 1
}
},
data() {
return {
activeTab: '0',
activeTab: 'temp_hum',
columns: {
airc: [
{
title: '名称',
dataIndex: 'pos',
key: 'pos',
ellipsis: true,
align: 'center'
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
ellipsis: true,
align: 'center'
}
],
cooling: [
{
title: '名称',
dataIndex: 'pos',
key: 'pos',
ellipsis: true,
align: 'center'
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
ellipsis: true,
align: 'center'
}
],
fire40: [
{
title: '点位',
dataIndex: 'pos',
key: 'pos',
ellipsis: true,
align: 'center'
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
ellipsis: true,
align: 'center'
}
],
'temp_hum': [
{
title: '点位',
dataIndex: 'pos',
key: 'pos',
ellipsis: true,
align: 'center'
},
{
title: '温度',
dataIndex: 'temp',
key: 'temp',
ellipsis: true,
align: 'center'
},
{
title: '湿度',
dataIndex: 'hum',
key: 'hum',
ellipsis: true,
align: 'center'
}
]
},
tabList: [
{
key: '0',
key: 'temp_hum',
name: '环境温湿度信息'
},
{
key: '1',
key: 'fire40',
name: '安防信息'
},
{
key: '2',
key: 'airc',
name: '空调信息'
},
{
key: '3',
key: 'cooling',
name: '冷机信息'
}
],
columns: [
{
title: '点位',
dataIndex: 'policyId',
key: 'policyId',
ellipsis: true
},
{
title: '温度',
dataIndex: 'name',
key: 'name',
ellipsis: true
},
{
title: '湿度',
dataIndex: 'type',
key: 'type',
ellipsis: true
}
],
tableDatas: {},
tableOption: {
select: false,
page: false
}
}
},
mounted() {},
methods: {}
mounted() {
this.getEnvironment()
},
methods: {
async getEnvironment() {
try {
const res = await getReq('/queryEnvironment', { station_id: this.stationId })
console.log(res, '==============')
this.tableDatas = res.data
// this.deviceList=res.data
} catch (error) {
console.log(error)
}
}
}
}
</script>
<style lang="scss" scoped>
.videos {
width: 60%;
width: calc(100% - 470px);
margin-left: 20px;
display: grid;
grid-gap: 20px;
@@ -130,7 +207,7 @@ export default {
}
}
.environment {
width: calc(40% - 20px);
width: 430px;
margin-left: 20px;
color: #fff;
@@ -187,6 +264,7 @@ export default {
}
.table-content {
margin-top: 20px;
height: calc(100% - 60px);
:deep(.ant-table) {
border-radius: 10px 10px 0 0 !important;
overflow: hidden; /* 确保圆角生效 */