feat(首页index): 重构首页布局并添加设备树功能

- 重新设计了首页布局,增加了左侧设备树和右侧内容区
- 实现了设备树数据加载和节点点击事件处理
- 优化了统计卡片和设备监控数据的展示样式
- 新增了根据设备树节点加载对应设备数据的功能
- 调整了响应式布局
boardTest
zch 4 weeks ago
parent 5e53e0d7ec
commit 5699dd4f73

@ -59,3 +59,11 @@ export function getLatestRecords() {
method: 'get'
})
}
// 根据父节点ID获取子设备的最新数据
export function getLatestRecordsByParentId(parentId) {
return request({
url: '/ems/record/recordIotenvInstant/getLatestRecordsByParentId/' + parentId,
method: 'get'
})
}

@ -17,16 +17,16 @@
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="能源类型" prop="energyTypeId">
<el-select v-model="queryParams.energyTypeId" placeholder="请选择能源类型">
<el-option
v-for="item in energyTypeList"
:key="item.energyTypeId"
:label="item.energyName"
:value="item.energyTypeId"
></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="能源类型" prop="energyTypeId">-->
<!-- <el-select v-model="queryParams.energyTypeId" placeholder="请选择能源类型">-->
<!-- <el-option-->
<!-- v-for="item in energyTypeList"-->
<!-- :key="item.energyTypeId"-->
<!-- :label="item.energyName"-->
<!-- :value="item.energyTypeId"-->
<!-- ></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item label="启用标识" prop="isFlag">
<el-select v-model="queryParams.isFlag" placeholder="请选择启用标识" clearable>
<el-option
@ -153,16 +153,16 @@
<el-form-item label="采集设备名称" prop="collectDeviceName">
<el-input v-model="form.collectDeviceName" placeholder="请输入采集设备名称"/>
</el-form-item>
<el-form-item label="能源类型" prop="energyTypeId">
<el-select v-model="form.energyTypeId" placeholder="请选择能源类型编号">
<el-option
v-for="item in energyTypeList"
:key="item.energyTypeId"
:label="item.energyName"
:value="item.energyTypeId"
></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="能源类型" prop="energyTypeId">-->
<!-- <el-select v-model="form.energyTypeId" placeholder="请选择能源类型编号">-->
<!-- <el-option-->
<!-- v-for="item in energyTypeList"-->
<!-- :key="item.energyTypeId"-->
<!-- :label="item.energyName"-->
<!-- :value="item.energyTypeId"-->
<!-- ></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item label="型号" prop="model">
<el-input v-model="form.model" placeholder="请输入型号"/>
</el-form-item>
@ -266,15 +266,15 @@ export default {
collectDeviceName: [
{ required: true, message: '采集设备名称不能为空', trigger: 'blur' }
],
energyTypeId: [
{ required: true, message: '能源类型不能为空', trigger: 'blur' }
]
// energyTypeId: [
// { required: true, message: '', trigger: 'blur' }
// ]
},
columns: [
{ key: 0, label: `自增标识`, visible: false },
{ key: 1, label: `采集设备编号`, visible: true },
{ key: 2, label: `采集设备名称`, visible: true },
{ key: 3, label: `能源类型`, visible: true },
{ key: 3, label: `能源类型`, visible: false },
{ key: 4, label: `型号`, visible: true },
{ key: 5, label: `生产厂家`, visible: true },
{ key: 6, label: `通讯地址`, visible: true },

@ -53,47 +53,47 @@
<el-table v-if="refreshTable" v-loading="loading" :data="baseMonitorInfoList" row-key="objId"
:default-expand-all="isExpandAll" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
<el-table-column label="父级编号" prop="parentId" v-if="columns[1].visible" />
<el-table-column label="计量设备编号" align="center" prop="monitorCode" v-if="columns[2].visible" />
<el-table-column label="计量设备名称" align="center" prop="monitorName" v-if="columns[3].visible" />
<el-table-column label="父级编号" prop="parentId" v-if="columns[0].visible" />
<el-table-column label="计量设备编号" align="center" prop="monitorCode" v-if="columns[1].visible" />
<el-table-column label="计量设备名称" align="center" prop="monitorName" v-if="columns[2].visible" />
<!-- <el-table-column label="能源类型" align="center" prop="monitorType" v-if="columns[4].visible">
<template slot-scope="scope">
{{ dict.type.monitor_type.find(e=>e.value == scope.row.monitorType).label}}
</template>
</el-table-column> -->
<el-table-column label="能源类型" align="center" prop="energyName" v-if="columns[4].visible">
<el-table-column label="能源类型" align="center" prop="energyName" v-if="columns[3].visible">
</el-table-column>
<el-table-column label="计量设备位置" align="center" prop="monitorAddr" v-if="columns[5].visible" />
<el-table-column label="计量设备状态" align="center" prop="monitorStatus" v-if="columns[6].visible">
<el-table-column label="计量设备位置" align="center" prop="monitorAddr" v-if="columns[4].visible" />
<el-table-column label="计量设备状态" align="center" prop="monitorStatus" v-if="columns[5].visible">
<template slot-scope="scope">
<dict-tag :options="dict.type.monitor_status" :value="scope.row.monitorStatus" />
</template>
</el-table-column>
<el-table-column label="采集设备编号" align="center" prop="collectDeviceId" v-if="columns[7].visible" />
<el-table-column label="等级" align="center" prop="grade" v-if="columns[9].visible" />
<el-table-column label="传感器仪表" align="center" prop="meterTypeId" v-if="columns[10].visible" />
<el-table-column label="修正值" align="center" prop="correctValue" v-if="columns[11].visible" />
<el-table-column label="是否虚拟" align="center" prop="isAmmeter" v-if="columns[14].visible">
<el-table-column label="采集设备编号" align="center" prop="collectDeviceId" v-if="columns[6].visible" />
<el-table-column label="等级" align="center" prop="grade" v-if="columns[7].visible" />
<el-table-column label="传感器仪表" align="center" prop="meterTypeId" v-if="columns[8].visible" />
<el-table-column label="修正值" align="center" prop="correctValue" v-if="columns[9].visible" />
<el-table-column label="是否虚拟" align="center" prop="isAmmeter" v-if="columns[10].visible">
<template slot-scope="scope">
<dict-tag :options="dict.type.is_ammeter" :value="scope.row.isAmmeter" />
</template>
</el-table-column>
<el-table-column label="通断复位" align="center" prop="isKeyMonitor" v-if="columns[15].visible" />
<el-table-column label="是否断路" align="center" prop="isCircuit" v-if="columns[16].visible" />
<el-table-column label="创建人" align="center" prop="createBy" v-if="columns[17].visible" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180" v-if="columns[18].visible">
<el-table-column label="通断复位" align="center" prop="isKeyMonitor" v-if="columns[11].visible" />
<el-table-column label="是否断路" align="center" prop="isCircuit" v-if="columns[12].visible" />
<el-table-column label="创建人" align="center" prop="createBy" v-if="columns[13].visible" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180" v-if="columns[14].visible">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="更新人" align="center" prop="updateBy" v-if="columns[19].visible" />
<el-table-column label="更新时间" align="center" prop="updateTime" width="180" v-if="columns[20].visible">
<el-table-column label="更新人" align="center" prop="updateBy" v-if="columns[15].visible" />
<el-table-column label="更新时间" align="center" prop="updateTime" width="180" v-if="columns[16].visible">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.updateTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="公摊表类型" align="center" prop="publicShareType" v-if="columns[21].visible" />
<el-table-column label="表具层级" align="center" prop="monitorHierarchy" v-if="columns[22].visible" />
<el-table-column label="公摊表类型" align="center" prop="publicShareType" v-if="columns[17].visible" />
<el-table-column label="表具层级" align="center" prop="monitorHierarchy" v-if="columns[18].visible" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="240">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
@ -101,7 +101,8 @@
<el-button size="mini" type="text" icon="el-icon-plus" @click="handleAdd(scope.row)"
v-hasPermi="['ems/base:baseMonitorInfo:add']">新增</el-button>
<el-button size="mini" type="text" icon="el-icon-setting" @click="handleThreshold(scope.row)"
v-hasPermi="['ems/record:recordAlarmRule:list']">阈值</el-button>
v-hasPermi="['ems/record:recordAlarmRule:list']"
v-if="scope.row.isAmmeter !== '0'">阈值</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['ems/base:baseMonitorInfo:remove']">删除</el-button>
</template>
@ -136,9 +137,9 @@
:label="parseInt(dict.value)">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
<!-- <el-form-item label="采集设备编号" prop="collectDeviceId">-->
<!-- <el-input v-model="form.collectDeviceId" placeholder="请输入采集设备编号" />-->
<!-- </el-form-item>-->
<el-form-item label="采集设备编号" prop="collectDeviceId">
<el-input v-model="form.collectDeviceId" placeholder="请输入采集设备编号" />
</el-form-item>
<!-- <el-form-item label="等级" prop="grade">-->
<!-- <el-input v-model="form.grade" placeholder="请输入等级" />-->
<!-- </el-form-item>-->
@ -354,30 +355,29 @@ export default {
],
},
columns: [
{ key: 0, label: `自增标识`, visible: false },
{ key: 1, label: `父级编号`, visible: false },
{ key: 2, label: `计量设备编号`, visible: true },
{ key: 3, label: `计量设备名称`, visible: true },
// { key: 0, label: ``, visible: false },
{ key: 0, label: `父级编号`, visible: false },
{ key: 1, label: `计量设备编号`, visible: true },
{ key: 2, label: `计量设备名称`, visible: true },
{ key: 3, label: `能源类型`, visible: true },
{ key: 4, label: `计量设备位置`, visible: true },
{ key: 5, label: `计量设备类型`, visible: true },
{ key: 6, label: `计量设备状态`, visible: true },
{ key: 7, label: `采集设备编号`, visible: false },
{ key: 8, label: `祖级列表`, visible: false },
{ key: 9, label: `等级`, visible: false },
{ key: 10, label: `传感器仪表`, visible: false },
{ key: 11, label: `修正值`, visible: false },
{ key: 12, label: `PT值`, visible: false },
{ key: 13, label: `CT值`, visible: false },
{ key: 14, label: `是否虚拟`, visible: true },
{ key: 15, label: `通断复位`, visible: false },
{ key: 16, label: `是否断路`, visible: false },
{ key: 17, label: `创建人`, visible: false },
{ key: 18, label: `创建时间`, visible: false },
{ key: 19, label: `更新人`, visible: false },
{ key: 20, label: `更新时间`, visible: false },
{ key: 21, label: `公摊表类型`, visible: false },
{ key: 22, label: `表具层级`, visible: false },
// { key: 5, label: ``, visible: true },
{ key: 5, label: `计量设备状态`, visible: true },
{ key: 6, label: `采集设备编号`, visible: false },
{ key: 7, label: `等级`, visible: false },
{ key: 8, label: `传感器仪表`, visible: false },
{ key: 9, label: `修正值`, visible: false },
// { key: 12, label: `PT`, visible: false },
// { key: 13, label: `CT`, visible: false },
{ key: 10, label: `是否虚拟`, visible: true },
{ key: 11, label: `通断复位`, visible: false },
{ key: 12, label: `是否断路`, visible: false },
{ key: 13, label: `创建人`, visible: false },
{ key: 14, label: `创建时间`, visible: false },
{ key: 15, label: `更新人`, visible: false },
{ key: 16, label: `更新时间`, visible: false },
{ key: 17, label: `公摊表类型`, visible: false },
{ key: 18, label: `表具层级`, visible: false },
],
//
energyTypeList: [],

@ -1,162 +1,198 @@
<template>
<div class="dashboard-container">
<!-- 页面标题 -->
<!-- <div class="page-header">-->
<!-- <h1 class="page-title">机场行李系统设备健康监测系统</h1>-->
<!-- <div class="page-subtitle">首页</div>-->
<!-- </div>-->
<!-- 统计卡片区域 -->
<div class="stats-section">
<div class="stats-grid">
<div class="stat-card total">
<div class="stat-icon">
<i class="el-icon-monitor"></i>
</div>
<div class="stat-content">
<div class="stat-number">{{ totalDeviceCount }}</div>
<div class="stat-label">设备总数</div>
</div>
</div>
<div class="stat-card alarm-rule">
<div class="stat-icon">
<i class="el-icon-warning"></i>
</div>
<div class="stat-content">
<div class="stat-number">{{ alarmRuleTotalCount }}</div>
<div class="stat-label">异常规则数量</div>
</div>
</div>
<div class="stat-card alarm-data">
<div class="stat-icon">
<i class="el-icon-bell"></i>
</div>
<div class="stat-content">
<div class="stat-number">{{ alarmDataTotalCount }}</div>
<div class="stat-label">异常数据数量</div>
</div>
</div>
</div>
</div>
<!-- 设备监控数据区域 -->
<div class="monitoring-section">
<div class="section-header">
<h2 class="section-title">设备监控数据</h2>
<div class="section-actions">
<el-button
type="primary"
icon="el-icon-refresh"
<div class="app-container">
<el-row :gutter="20">
<!-- 左侧设备树 -->
<el-col :span="5" :xs="24">
<div class="head-container">
<el-input
v-model="deviceTreeFilter"
placeholder="请输入设备名称"
clearable
size="small"
@click="refreshData"
:loading="loading">
刷新数据
</el-button>
prefix-icon="el-icon-search"
style="margin-bottom: 20px"
/>
</div>
</div>
<div class="head-container">
<el-tree
:data="deviceTreeOptions"
:props="deviceTreeProps"
:expand-on-click-node="false"
:filter-node-method="filterDeviceNode"
ref="deviceTree"
node-key="id"
default-expand-all
highlight-current
@node-click="handleDeviceNodeClick">
</el-tree>
</div>
</el-col>
<!-- 设备数据卡片网格 -->
<div class="device-grid" v-loading="loading">
<div
v-for="device in deviceList"
:key="device.monitorId"
class="device-card"
:class="getDeviceStatus(device)">
<!-- 设备头部信息 -->
<div class="device-header">
<div class="device-info">
<h3 class="device-name">{{ device.monitorName || '未知设备' }}</h3>
<span class="device-id">{{ device.monitorId }}</span>
</div>
<div class="device-status">
<span class="status-indicator" :class="getDeviceStatus(device)"></span>
<span class="status-text">{{ getStatusText(device) }}</span>
</div>
</div>
<!-- 设备数据展示 -->
<div class="device-data">
<div class="data-row" v-if="device.temperature !== null && device.temperature !== undefined">
<div class="data-item">
<i class="data-icon el-icon-thermometer"></i>
<span class="data-label">温度</span>
<span class="data-value">{{ formatValue(device.temperature, '°C') }}</span>
<!-- 右侧内容区 -->
<el-col :span="19" :xs="24">
<!-- 统计卡片区域 -->
<div class="stats-section">
<div class="stats-grid">
<div class="stat-card total">
<div class="stat-icon">
<i class="el-icon-monitor"></i>
</div>
<div class="stat-content">
<div class="stat-number">{{ totalDeviceCount }}</div>
<div class="stat-label">设备总数</div>
</div>
</div>
<div class="data-row" v-if="device.humidity !== null && device.humidity !== undefined">
<div class="data-item">
<i class="data-icon el-icon-cloudy"></i>
<span class="data-label">湿度</span>
<span class="data-value">{{ formatValue(device.humidity, '%') }}</span>
<div class="stat-card alarm-rule">
<div class="stat-icon">
<i class="el-icon-warning"></i>
</div>
<div class="stat-content">
<div class="stat-number">{{ alarmRuleTotalCount }}</div>
<div class="stat-label">异常规则数量</div>
</div>
</div>
<div class="data-row" v-if="device.noise !== null && device.noise !== undefined">
<div class="data-item">
<i class="data-icon el-icon-microphone"></i>
<span class="data-label">噪声</span>
<span class="data-value">{{ formatValue(device.noise, 'dB') }}</span>
<div class="stat-card alarm-data">
<div class="stat-icon">
<i class="el-icon-bell"></i>
</div>
<div class="stat-content">
<div class="stat-number">{{ alarmDataTotalCount }}</div>
<div class="stat-label">异常数据数量</div>
</div>
</div>
<div class="data-row" v-if="device.illuminance !== null && device.illuminance !== undefined">
<div class="data-item">
<i class="data-icon el-icon-sunny"></i>
<span class="data-label">照度</span>
<span class="data-value">{{ formatValue(device.illuminance, 'lx') }}</span>
</div>
</div>
<div class="data-row" v-if="device.concentration !== null && device.concentration !== undefined">
<div class="data-item">
<i class="data-icon el-icon-warning-outline"></i>
<span class="data-label">硫化氢</span>
<span class="data-value">{{ formatValue(device.concentration, 'ppm') }}</span>
</div>
</div>
<div class="data-row" v-if="device.vibrationSpeed !== null && device.vibrationSpeed !== undefined">
<div class="data-item">
<i class="data-icon el-icon-s-operation"></i>
<span class="data-label">振动速度</span>
<span class="data-value">{{ formatValue(device.vibrationSpeed, 'mm/s') }}</span>
</div>
</div>
<!-- 无数据提示 -->
<div v-if="!hasData(device)" class="no-data">
<i class="el-icon-warning-outline"></i>
<span>当天无最新数据</span>
</div>
</div>
<!-- 设备底部信息 -->
<div class="device-footer" v-if="device.recodeTime">
<span class="update-time">
<i class="el-icon-time"></i>
记录时间{{ formatTime(device.recodeTime) }}
</span>
</div>
</div>
</div>
<!-- 空状态 -->
<div v-if="!loading && deviceList.length === 0" class="empty-state">
<i class="el-icon-box"></i>
<p>暂无设备数据</p>
</div>
</div>
<!-- 设备监控数据区域 -->
<div class="monitoring-section">
<div class="section-header">
<h2 class="section-title">设备监控数据</h2>
<div class="section-actions">
<span v-if="selectedNodeName" class="selected-node">
当前节点{{ selectedNodeName }}
</span>
<el-button
type="primary"
icon="el-icon-refresh"
size="small"
@click="refreshData"
:loading="loading">
刷新数据
</el-button>
</div>
</div>
<!-- 设备数据卡片网格 -->
<div class="device-grid" v-loading="loading">
<div
v-for="device in filteredDeviceList"
:key="device.monitorId"
class="device-card"
:class="getDeviceStatus(device)">
<!-- 设备头部信息 -->
<div class="device-header">
<div class="device-info">
<h3 class="device-name">{{ device.monitorName || '未知设备' }}</h3>
<span class="device-id">{{ device.monitorId }}</span>
</div>
<div class="device-status">
<span class="status-indicator" :class="getDeviceStatus(device)"></span>
<span class="status-text">{{ getStatusText(device) }}</span>
</div>
</div>
<!-- 设备数据展示 -->
<div class="device-data">
<div class="data-row" v-if="device.temperature !== null && device.temperature !== undefined">
<div class="data-item">
<i class="data-icon el-icon-thermometer"></i>
<span class="data-label">温度</span>
<span class="data-value">{{ formatValue(device.temperature, '°C') }}</span>
</div>
</div>
<div class="data-row" v-if="device.humidity !== null && device.humidity !== undefined">
<div class="data-item">
<i class="data-icon el-icon-cloudy"></i>
<span class="data-label">湿度</span>
<span class="data-value">{{ formatValue(device.humidity, '%') }}</span>
</div>
</div>
<div class="data-row" v-if="device.noise !== null && device.noise !== undefined">
<div class="data-item">
<i class="data-icon el-icon-microphone"></i>
<span class="data-label">噪声</span>
<span class="data-value">{{ formatValue(device.noise, 'dB') }}</span>
</div>
</div>
<div class="data-row" v-if="device.illuminance !== null && device.illuminance !== undefined">
<div class="data-item">
<i class="data-icon el-icon-sunny"></i>
<span class="data-label">照度</span>
<span class="data-value">{{ formatValue(device.illuminance, 'lx') }}</span>
</div>
</div>
<div class="data-row" v-if="device.concentration !== null && device.concentration !== undefined">
<div class="data-item">
<i class="data-icon el-icon-warning-outline"></i>
<span class="data-label">硫化氢</span>
<span class="data-value">{{ formatValue(device.concentration, 'ppm') }}</span>
</div>
</div>
<div class="data-row" v-if="device.vibrationSpeed !== null && device.vibrationSpeed !== undefined">
<div class="data-item">
<i class="data-icon el-icon-s-operation"></i>
<span class="data-label">振动速度</span>
<span class="data-value">{{ formatValue(device.vibrationSpeed, 'mm/s') }}</span>
</div>
</div>
<!-- 无数据提示 -->
<div v-if="!hasData(device)" class="no-data">
<i class="el-icon-warning-outline"></i>
<span>当天无最新数据</span>
</div>
</div>
<!-- 设备底部信息 -->
<div class="device-footer" v-if="device.recodeTime">
<span class="update-time">
<i class="el-icon-time"></i>
记录时间{{ formatTime(device.recodeTime) }}
</span>
</div>
</div>
</div>
<!-- 空状态 -->
<div v-if="!loading && filteredDeviceList.length === 0 && selectedNodeName" class="empty-state">
<i class="el-icon-box"></i>
<p>该节点下暂无设备数据</p>
</div>
<!-- 未选择提示 -->
<div v-if="!selectedNodeName && !loading" class="empty-state">
<i class="el-icon-s-grid"></i>
<p>请在设备树中选择节点查看设备数据</p>
</div>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import { getLatestRecords } from '@/api/ems/record/recordIotenvInstant'
import { getLatestRecords, getLatestRecordsByParentId } from '@/api/ems/record/recordIotenvInstant'
import {getAlarmDataTotalCount} from "@/api/ems/record/recordAlarmData";
import {getEmsRecordAlarmRuleTotalCount} from "@/api/ems/record/recordAlarmRule";
import { getMonitorInfoTree } from '@/api/ems/base/baseMonitorInfo';
export default {
name: 'Dashboard',
@ -165,20 +201,41 @@ export default {
loading: false,
deviceList: [],
refreshTimer: null,
alarmRuleTotalCount:0,
alarmDataTotalCount:0
alarmRuleTotalCount: 0,
alarmDataTotalCount: 0,
totalDeviceCount: 0, //
//
deviceTreeOptions: [],
deviceTreeFilter: '',
selectedNodeId: null, // ID
selectedNodeName: null, //
deviceTreeProps: {
children: 'children',
label: 'label'
}
}
},
computed: {
totalDeviceCount() {
return this.deviceList.length
//
filteredDeviceList() {
return this.deviceList
}
},
watch: {
//
deviceTreeFilter(val) {
this.$refs.deviceTree.filter(val)
}
},
mounted() {
this.loadDeviceData()
// 1
this.loadDeviceTree()
this.loadStatistics() //
// 1
this.refreshTimer = setInterval(() => {
this.loadDeviceData()
if (this.selectedNodeId !== null) {
this.loadDeviceDataByNode(this.selectedNodeId)
}
this.loadStatistics()
}, 60000)
},
beforeDestroy() {
@ -187,12 +244,31 @@ export default {
}
},
methods: {
async loadDeviceData() {
this.loading = true
async loadStatistics() {
try {
this.alarmDataTotalCount = await getAlarmDataTotalCount();
this.alarmRuleTotalCount = await getEmsRecordAlarmRuleTotalCount();
//
const response = await getLatestRecords()
if (response.code === 200) {
const rawData = response.data || []
const allDevices = rawData.filter(device => {
return device.monitorName !== '胶东机场' &&
device.monitorId &&
device.monitorName
})
//
this.totalDeviceCount = allDevices.length
}
} catch (error) {
console.error('获取统计数据失败:', error)
}
},
async loadDeviceDataByNode(parentId) {
this.loading = true
try {
const response = await getLatestRecordsByParentId(parentId)
if (response.code === 200) {
//
const rawData = response.data || []
@ -204,27 +280,52 @@ export default {
device.monitorId &&
device.monitorName
})
console.log('原始设备数据:', rawData)
console.log('过滤后设备数据:', this.deviceList)
//
const filteredCount = rawData.length - this.deviceList.length
if (filteredCount > 0) {
console.log(`已过滤掉 ${filteredCount} 条异常数据`)
}
console.log('选中节点设备数据:', this.deviceList)
} else {
this.$message.error(response.msg || '获取设备数据失败')
this.deviceList = []
}
} catch (error) {
console.error('获取设备数据失败:', error)
this.$message.error('获取设备数据失败')
this.deviceList = []
} finally {
this.loading = false
}
},
refreshData() {
this.loadDeviceData()
if (this.selectedNodeId !== null) {
this.loadDeviceDataByNode(this.selectedNodeId)
}
this.loadStatistics()
},
//
async loadDeviceTree() {
const response = await getMonitorInfoTree({})
this.deviceTreeOptions = response.data || []
console.log('设备树数据:', this.deviceTreeOptions)
},
//
filterDeviceNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
//
handleDeviceNodeClick(data) {
console.log('点击设备树节点:', data)
//
this.selectedNodeId = data.id
this.selectedNodeName = data.label
console.log('选中节点ID:', this.selectedNodeId, '节点名称:', this.selectedNodeName)
// ID
this.loadDeviceDataByNode(this.selectedNodeId)
},
hasData(device) {
@ -300,36 +401,56 @@ export default {
</script>
<style lang="scss" scoped>
.dashboard-container {
.app-container {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.page-header {
text-align: center;
margin-bottom: 30px;
//
.head-container {
background: white;
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
.page-title {
font-size: 28px;
font-weight: 600;
color: #2c3e50;
margin: 0 0 8px 0;
.el-tree {
background: transparent;
}
.page-subtitle {
font-size: 16px;
color: #7f8c8d;
.el-tree-node__content {
height: 32px;
line-height: 32px;
border-radius: 6px;
margin-bottom: 2px;
&:hover {
background-color: #f5f7fa;
}
}
.el-tree-node.is-current > .el-tree-node__content {
background-color: #ecf5ff;
color: #409eff;
}
.el-tree-node__expand-icon {
color: #c0c4cc;
&.is-leaf {
color: transparent;
}
}
}
//
.stats-section {
margin-bottom: 30px;
margin-bottom: 20px;
.stats-grid {
display: flex;
justify-content: center;
gap: 20px;
gap: 16px;
flex-wrap: wrap;
}
@ -341,7 +462,8 @@ export default {
display: flex;
align-items: center;
transition: transform 0.3s ease, box-shadow 0.3s ease;
min-width: 220px;
min-width: 200px;
flex: 1;
&:hover {
transform: translateY(-2px);
@ -367,7 +489,7 @@ export default {
flex: 1;
.stat-number {
font-size: 28px;
font-size: 24px;
font-weight: 700;
line-height: 1;
margin-bottom: 4px;
@ -408,39 +530,61 @@ export default {
}
}
//
.monitoring-section {
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 1px solid #e9ecef;
.section-title {
font-size: 20px;
font-size: 18px;
font-weight: 600;
color: #2c3e50;
margin: 0;
}
.section-actions {
display: flex;
align-items: center;
gap: 12px;
.selected-node {
font-size: 14px;
color: #409eff;
background: #ecf5ff;
padding: 4px 12px;
border-radius: 4px;
border: 1px solid #d9ecff;
}
}
}
.device-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}
.device-card {
background: white;
background: #f8f9fa;
border-radius: 10px;
padding: 10px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
padding: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
border-left: 4px solid #e9ecef;
font-size: 0.92em;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
&.normal {
@ -480,7 +624,7 @@ export default {
.device-id {
font-size: 12px;
color: #7f8c8d;
background: #f8f9fa;
background: white;
padding: 2px 8px;
border-radius: 4px;
}
@ -567,9 +711,9 @@ export default {
}
.device-footer {
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid #f0f0f0;
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #e9ecef;
.update-time {
font-size: 11px;
@ -599,14 +743,14 @@ export default {
}
}
//
@media (max-width: 768px) {
.dashboard-container {
.app-container {
padding: 16px;
}
.stats-grid {
flex-direction: column;
align-items: center;
}
.device-grid {
@ -617,6 +761,11 @@ export default {
flex-direction: column;
align-items: flex-start;
gap: 12px;
.section-actions {
width: 100%;
justify-content: space-between;
}
}
}
</style>

@ -161,8 +161,7 @@ export default {
justify-content: center;
align-items: center;
height: 100%;
//background-image: url("../assets/images/login-background.jpg");
background-image: url("../assets/images/mesnac.jpg");
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {

Loading…
Cancel
Save