|
|
@@ -1,206 +1,908 @@
|
|
|
-<template>
|
|
|
- <div class="ele-body">
|
|
|
- <el-card shadow="never" v-loading="loading">
|
|
|
- <el-tabs v-model="activeName" type="card">
|
|
|
- <el-tab-pane label="全部" name="all"></el-tab-pane>
|
|
|
- <el-tab-pane label="占用" name="1"></el-tab-pane>
|
|
|
- <el-tab-pane label="巡点检" name="2"></el-tab-pane>
|
|
|
- <el-tab-pane label="保养" name="3"></el-tab-pane>
|
|
|
- <el-tab-pane label="故障" name="4"></el-tab-pane>
|
|
|
- <el-tab-pane label="维修" name="5"></el-tab-pane>
|
|
|
- <el-tab-pane label="空闲" name="6"></el-tab-pane>
|
|
|
- </el-tabs>
|
|
|
- <seekPage style="margin-top: 10px;" :seekList="seekList" :formLength="3"></seekPage>
|
|
|
- <!-- 数据表格 -->
|
|
|
- <ele-pro-table
|
|
|
- ref="table"
:pageSizes="tablePageSizes"
|
|
|
- :columns="columns"
|
|
|
- :datasource="datasource"
|
|
|
- cache-key="systemRoleTable"
|
|
|
- >
|
|
|
- </ele-pro-table>
|
|
|
- </el-card>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script>
|
|
|
- import dictMixins from '@/mixins/dictMixins';
|
|
|
- export default {
|
|
|
- mixins: [dictMixins],
|
|
|
- components: {},
|
|
|
- data() {
|
|
|
- return {
|
|
|
- activeName: 'all',
|
|
|
- // 表格列配置
|
|
|
- columns: [
|
|
|
- {
|
|
|
- columnKey: 'index',
|
|
|
- label: '序号',
|
|
|
- type: 'index',
|
|
|
- width: 55,
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- fixed: 'left'
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status',
|
|
|
- label: '分类',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status1',
|
|
|
- label: '权属部门',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'statu2s',
|
|
|
- label: '设备名称',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status3',
|
|
|
- label: '设备编号',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status4',
|
|
|
- label: '状态',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status5',
|
|
|
- label: '监测时间',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status6',
|
|
|
- label: '蒸汽出口压力',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status8',
|
|
|
- label: '蒸汽出口干度',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status9',
|
|
|
- label: '热能交换器进口压力',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status10',
|
|
|
- label: '热能交换器出口压力',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status11',
|
|
|
- label: '热能交换器出口温度',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status12',
|
|
|
- label: '给水泵入口压力',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status13',
|
|
|
- label: '给水泵出口压力',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status14',
|
|
|
- label: '高温过热器温度',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status15',
|
|
|
- label: '返料器温度',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status16',
|
|
|
- label: '排烟温度',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status17',
|
|
|
- label: '水量',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- },
|
|
|
- {
|
|
|
- prop: 'status18',
|
|
|
- label: '注汽量',
|
|
|
- align: 'center',
|
|
|
- showOverflowTooltip: true,
|
|
|
- minWidth: 110
|
|
|
- }
|
|
|
- ],
|
|
|
- seekList: [
|
|
|
- {
|
|
|
- label: '关键字:',
|
|
|
- value: 'searchName',
|
|
|
- type: 'input',
|
|
|
- placeholder: '编码/名称'
|
|
|
- },
|
|
|
- {
|
|
|
- label: '权属部门:',
|
|
|
- value: 'codeOrSerialNo',
|
|
|
- type: 'input',
|
|
|
- placeholder: '请输入'
|
|
|
- },
|
|
|
- {
|
|
|
- label: '状态',
|
|
|
- value: 'name',
|
|
|
- type: 'input',
|
|
|
- placeholder: '请输入'
|
|
|
- }
|
|
|
- ]
|
|
|
- // 加载状态
|
|
|
- };
|
|
|
- },
|
|
|
- computed: {},
|
|
|
- created() {},
|
|
|
- methods: {
|
|
|
- /* 表格数据源 */
|
|
|
- datasource({ page, limit, where, order }) {
|
|
|
- return [];
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
-</script>
|
|
|
-
|
|
|
-<style lang="scss" scoped></style>
|
|
|
+<template>
|
|
|
+ <div class="energy-monitoring card-mode">
|
|
|
+ <el-card shadow="never" class="monitoring-card card-mode">
|
|
|
+ <!-- 主内容区 -->
|
|
|
+ <ele-split-layout
|
|
|
+ width="220px"
|
|
|
+ allow-collapse
|
|
|
+ :right-style="{ overflow: 'hidden' }"
|
|
|
+ >
|
|
|
+ <!-- 左侧树形菜单 -->
|
|
|
+ <div class="left-sidebar card-mode">
|
|
|
+ <el-tabs
|
|
|
+ v-model="activeTab"
|
|
|
+ type="border-card"
|
|
|
+ @tab-click="activeTabChange"
|
|
|
+ >
|
|
|
+ <el-tab-pane label="设备类型" name="org">
|
|
|
+ <el-tree
|
|
|
+ :data="orgTreeData"
|
|
|
+ :props="treeProps"
|
|
|
+ node-key="id"
|
|
|
+ highlight-current
|
|
|
+ @node-click="handleNodeClick"
|
|
|
+ style="height: calc(100vh - 180px)"
|
|
|
+ ref="treeRef"
|
|
|
+ ></el-tree>
|
|
|
+ </el-tab-pane>
|
|
|
+ <el-tab-pane label="用能分区" name="energy">
|
|
|
+ <el-tree
|
|
|
+ :data="treeData"
|
|
|
+ :props="treeProps"
|
|
|
+ node-key="id"
|
|
|
+ default-expand-all
|
|
|
+ ref="treeRef1"
|
|
|
+ highlight-current
|
|
|
+ @node-click="handleNodeClick"
|
|
|
+ ></el-tree>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 右侧内容区 -->
|
|
|
+ <template v-slot:content>
|
|
|
+ <div class="right-content card-mode">
|
|
|
+ <!-- 搜索区域 -->
|
|
|
+ <div class="search-area card-mode">
|
|
|
+ <!-- 设备状态标签 -->
|
|
|
+ <!-- <div class="status-tabs">
|
|
|
+ <el-radio-group
|
|
|
+ v-model="statusFilter"
|
|
|
+ size="small"
|
|
|
+ @change="handleStatusChange"
|
|
|
+ >
|
|
|
+ <el-radio-button label="all">全部</el-radio-button>
|
|
|
+ <el-radio-button label="online">在线</el-radio-button>
|
|
|
+ <el-radio-button label="offline">离线</el-radio-button>
|
|
|
+ <el-radio-button label="fault">故障</el-radio-button>
|
|
|
+ </el-radio-group>
|
|
|
+ </div> -->
|
|
|
+ <!-- 搜索框 -->
|
|
|
+ <div class="search-input-wrapper">
|
|
|
+ <el-input
|
|
|
+ v-model="name"
|
|
|
+ placeholder="请输入关键词"
|
|
|
+ prefix-icon="el-icon-search"
|
|
|
+ clearable
|
|
|
+ @keyup.enter.native="handleSearch"
|
|
|
+ style="width: 280px"
|
|
|
+ >
|
|
|
+ </el-input>
|
|
|
+ <el-button type="primary" @click="handleSearch">搜索</el-button>
|
|
|
+ <el-button @click="handleReset">重置</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 更新时间 -->
|
|
|
+ <div class="update-time">更新时间:{{ updateTime }}</div>
|
|
|
+
|
|
|
+ <!-- 卡片视图 -->
|
|
|
+ <div class="card-view">
|
|
|
+ <el-row :gutter="10">
|
|
|
+ <el-col
|
|
|
+ v-for="item in deviceData"
|
|
|
+ :key="item.id"
|
|
|
+ :xs="24"
|
|
|
+ :sm="12"
|
|
|
+ :md="8"
|
|
|
+ :lg="6"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="device-card"
|
|
|
+ :class="{ 'is-fault': item.status == '3'||item.status == '2' }"
|
|
|
+ @click="details(item)"
|
|
|
+ >
|
|
|
+ <div class="card-header">
|
|
|
+ <div class="device-name">{{ item.name }}</div>
|
|
|
+ <div class="card-actions">
|
|
|
+ <el-tag
|
|
|
+ :type="getStatusType(item.status, 1)"
|
|
|
+ size="small"
|
|
|
+ effect="dark"
|
|
|
+ class="status-tag"
|
|
|
+ >
|
|
|
+ {{
|
|
|
+ businessStatus.filter(
|
|
|
+ (row) => row.code == item.status
|
|
|
+ )[0]?.label
|
|
|
+ }}
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="card-body">
|
|
|
+ <el-tag
|
|
|
+ :type="getStatusType(item.networkStatus)"
|
|
|
+ size="small"
|
|
|
+ effect="dark"
|
|
|
+ class="status-tag"
|
|
|
+ >
|
|
|
+ {{ getStatusText(item.networkStatus) }}
|
|
|
+ </el-tag>
|
|
|
+ <div class="info-grid">
|
|
|
+ <div class="info-row" v-for="iotItem in item.iotList">
|
|
|
+ <span class="info-label">{{ iotItem.name }}</span>
|
|
|
+ <span class="info-value">{{
|
|
|
+ iotItem.dataType.type == 'enum' ||
|
|
|
+ iotItem.dataType.type == 'bool'
|
|
|
+ ? iotItem.dataType.specs[iotItem.value]
|
|
|
+ : iotItem.value +
|
|
|
+ ' ' +
|
|
|
+ ((iotItem.unit && iotItem.unit) || '')
|
|
|
+ }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 分页 -->
|
|
|
+ <div class="pagination-area">
|
|
|
+ <el-pagination
|
|
|
+ @size-change="handleSizeChange"
|
|
|
+ @current-change="handleCurrentChange"
|
|
|
+ :current-page="pageNum"
|
|
|
+ :page-sizes="[10, 20, 50, 100]"
|
|
|
+ :page-size="pageSize"
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ :total="total"
|
|
|
+ ></el-pagination>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </ele-split-layout>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+ import dictMixins from '@/mixins/dictMixins';
|
|
|
+ import tableColumnsMixin from '@/mixins/tableColumnsMixin';
|
|
|
+ import dayjs from 'dayjs';
|
|
|
+ import { querySubstanceRunningMonitor } from '@/api/ledgerAssets';
|
|
|
+ import { getTreeByPid } from '@/api/classifyManage';
|
|
|
+ import { basicAreaPageAPI } from '@/api/factoryModel';
|
|
|
+ import { businessStatus } from '@/utils/dict/warehouse';
|
|
|
+ import { data } from 'ele-admin/lib/ele-pro-table';
|
|
|
+ import d from 'highlight.js/lib/languages/d';
|
|
|
+ export default {
|
|
|
+ mixins: [dictMixins, tableColumnsMixin],
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ // 搜索表单
|
|
|
+ searchForm: {
|
|
|
+ energyType: '',
|
|
|
+ keyword: '',
|
|
|
+ deviceStatus: ''
|
|
|
+ },
|
|
|
+ businessStatus,
|
|
|
+
|
|
|
+ // 当前激活的标签页
|
|
|
+ activeTab: 'org',
|
|
|
+ // 更新时间
|
|
|
+ updateTime: dayjs().format('YYYY-M-D HH:mm:ss'),
|
|
|
+ // 搜索关键词
|
|
|
+ name: '',
|
|
|
+ // 树形数据
|
|
|
+ treeData: [],
|
|
|
+ orgTreeData: [],
|
|
|
+ treeProps: {
|
|
|
+ children: 'children',
|
|
|
+ label: 'name'
|
|
|
+ },
|
|
|
+ // 分页参数
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ total: 0,
|
|
|
+ areaId: '',
|
|
|
+
|
|
|
+ cacheKeyUrl: 'ems-energy-monitoring-list',
|
|
|
+ deviceData: [],
|
|
|
+ categoryLevelId: '',
|
|
|
+ rootCategoryLevelId: ''
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {},
|
|
|
+ created() {
|
|
|
+ getTreeByPid(0).then((res) => {
|
|
|
+ this.orgTreeData = res.data.filter((item) =>
|
|
|
+ [
|
|
|
+ '4',
|
|
|
+ '14',
|
|
|
+ '1812765052571865089',
|
|
|
+ '5',
|
|
|
+ '8',
|
|
|
+ '7',
|
|
|
+ '26',
|
|
|
+ '18',
|
|
|
+ '15',
|
|
|
+ '6',
|
|
|
+ '11',
|
|
|
+ '16'
|
|
|
+ ].includes(item.id)
|
|
|
+ );
|
|
|
+ if (this.orgTreeData.length) {
|
|
|
+ this.handleNodeClick(this.orgTreeData[0]);
|
|
|
+ this.$nextTick(() => {
|
|
|
+ console.log(this.orgTreeData[0].id, 'this.orgTreeData[0].id');
|
|
|
+ this.$refs.treeRef.setCurrentKey(this.orgTreeData[0].id);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ /* 获取区域集合 */
|
|
|
+
|
|
|
+ basicAreaPageAPI({
|
|
|
+ pageNum: 1,
|
|
|
+ size: 9999
|
|
|
+ }).then((res) => {
|
|
|
+ this.treeData = this.$util.toTreeData({
|
|
|
+ data: res,
|
|
|
+ idField: 'id',
|
|
|
+ parentIdField: 'parentId'
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ activeTabChange() {
|
|
|
+ let data = null;
|
|
|
+ this.pageNum = 1;
|
|
|
+ if (this.activeTab == 'org') {
|
|
|
+ data = this.orgTreeData[0];
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.$refs.treeRef.setCurrentKey(this.orgTreeData[0].id);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ data = this.treeData[0] || {};
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.$refs.treeRef1.setCurrentKey(this.treeData[0].id);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (data) {
|
|
|
+ this.handleNodeClick(data);
|
|
|
+ } else {
|
|
|
+ this.total = 0;
|
|
|
+ this.deviceData = [];
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 加载设备数据(模拟)
|
|
|
+ loadDeviceData() {
|
|
|
+ querySubstanceRunningMonitor({
|
|
|
+ pageNum: this.pageNum,
|
|
|
+ size: this.pageSize,
|
|
|
+ categoryLevelId: this.categoryLevelId,
|
|
|
+ rootCategoryLevelId: this.rootCategoryLevelId,
|
|
|
+ areaId: this.areaId,
|
|
|
+ name: this.name
|
|
|
+ }).then((res) => {
|
|
|
+ this.updateTime = dayjs().format('YYYY-M-D HH:mm:ss');
|
|
|
+ this.deviceData = res.list.map((item) => {
|
|
|
+ let iotList = [];
|
|
|
+ if (item.iotPointDataList) {
|
|
|
+ item.iotPointDataList.forEach((element) => {
|
|
|
+ let data = item.iotModel.properties.find(
|
|
|
+ (iotModel) => iotModel.identifier == element.identifier
|
|
|
+ );
|
|
|
+ if (data) {
|
|
|
+ iotList.push({
|
|
|
+ ...element,
|
|
|
+ dataType: data.dataType
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ item['iotList'] = item.iotDashboardPoint.length
|
|
|
+ ? iotList.filter((iotListItem) =>
|
|
|
+ item.iotDashboardPoint.find(
|
|
|
+ (Point) =>
|
|
|
+ Point.identifier == iotListItem.identifier &&
|
|
|
+ Point.checked1
|
|
|
+ )
|
|
|
+ )
|
|
|
+ : iotList.filter((iotListItem, index) => index < 4);
|
|
|
+ return item;
|
|
|
+ });
|
|
|
+ this.total = res.count;
|
|
|
+ console.log(res);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // // 获取设备图标
|
|
|
+ // getDeviceIcon(type) {
|
|
|
+ // const iconMap = {
|
|
|
+ // water: 'el-icon-water-cup',
|
|
|
+ // electric: 'el-icon-lightning',
|
|
|
+ // gas: 'el-icon-stopwatch'
|
|
|
+ // };
|
|
|
+ // return iconMap[type] || 'el-icon-odometer';
|
|
|
+ // },
|
|
|
+ // 获取状态类型
|
|
|
+ getStatusType(status, type) {
|
|
|
+ const typeMap = !type
|
|
|
+ ? {
|
|
|
+ 1: 'success',
|
|
|
+ 0: 'info',
|
|
|
+ fault: 'danger'
|
|
|
+ }
|
|
|
+ : {
|
|
|
+ // { code: 0, label: '空闲' },
|
|
|
+ // { code: 1, label: '占用' },
|
|
|
+ // { code: 2, label: '故障' },
|
|
|
+ // { code: 3, label: '维修' },
|
|
|
+ // { code: 4, label: '保养' },
|
|
|
+ // { code: 5, label: '巡点检' }
|
|
|
+
|
|
|
+ 0: 'success',
|
|
|
+ 1: 'success',
|
|
|
+ 4: 'success',
|
|
|
+ 5: 'success',
|
|
|
+
|
|
|
+ 2: 'danger',
|
|
|
+ 3: 'danger'
|
|
|
+ };
|
|
|
+ return typeMap[status];
|
|
|
+ },
|
|
|
+ // 获取状态文本
|
|
|
+ getStatusText(status) {
|
|
|
+ const textMap = {
|
|
|
+ 1: '在线',
|
|
|
+ 0: '离线',
|
|
|
+ fault: '故障'
|
|
|
+ };
|
|
|
+ return textMap[status] || status;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 搜索
|
|
|
+ handleSearch() {
|
|
|
+ this.pageNum = 1;
|
|
|
+ this.loadDeviceData();
|
|
|
+ },
|
|
|
+ // 重置
|
|
|
+ handleReset() {
|
|
|
+ this.name = '';
|
|
|
+ this.pageNum = 1;
|
|
|
+ this.loadDeviceData();
|
|
|
+ },
|
|
|
+ // 树节点点击
|
|
|
+ handleNodeClick(data) {
|
|
|
+ this.categoryLevelId = '';
|
|
|
+ this.rootCategoryLevelId = '';
|
|
|
+ this.areaId = '';
|
|
|
+ if (this.activeTab == 'org') {
|
|
|
+ this.categoryLevelId = data.id;
|
|
|
+ this.rootCategoryLevelId = data.rootCategoryLevelId;
|
|
|
+ } else {
|
|
|
+ this.areaId = data.id;
|
|
|
+ }
|
|
|
+ this.loadDeviceData();
|
|
|
+ },
|
|
|
+ // 卡片点击
|
|
|
+ // 跳转到详情页
|
|
|
+ details({ id, code, name }) {
|
|
|
+ this.$router.push({
|
|
|
+ path: '/ledgerAssets/equipment/detail',
|
|
|
+ query: {
|
|
|
+ id,
|
|
|
+ code,
|
|
|
+ name,
|
|
|
+ activeComp:'internet'
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 分页大小变化
|
|
|
+ handleSizeChange(val) {
|
|
|
+ this.pageSize = val;
|
|
|
+ this.loadDeviceData();
|
|
|
+ },
|
|
|
+ // 页码变化
|
|
|
+ handleCurrentChange(val) {
|
|
|
+ this.pageNum = val;
|
|
|
+ this.loadDeviceData();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+ .energy-monitoring {
|
|
|
+ min-height: calc(100vh - 96px);
|
|
|
+ // padding: 15px;
|
|
|
+
|
|
|
+ .monitoring-card {
|
|
|
+ height: calc(100vh - 96px);
|
|
|
+
|
|
|
+ ::v-deep .el-card__body {
|
|
|
+ height: 100%;
|
|
|
+ padding: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.card-mode {
|
|
|
+ background: linear-gradient(
|
|
|
+ 135deg,
|
|
|
+ #1a1c2e 0%,
|
|
|
+ #161825 100%
|
|
|
+ ) !important;
|
|
|
+ border-color: rgba(255, 255, 255, 0.1) !important;
|
|
|
+
|
|
|
+ ::v-deep .el-card__body {
|
|
|
+ background: transparent;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .ele-split-layout {
|
|
|
+ .ele-split-layout-left {
|
|
|
+ padding: 0;
|
|
|
+ background: transparent;
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ele-split-layout-right {
|
|
|
+ padding: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ele-split-layout-trigger {
|
|
|
+ width: 8px;
|
|
|
+ background: #f0f0f0;
|
|
|
+ border-left: 1px solid #e0e0e0;
|
|
|
+ border-right: 1px solid #e0e0e0;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: #d0d0d0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ele-split-layout-trigger-icon {
|
|
|
+ color: #909399;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .left-sidebar {
|
|
|
+ height: 100%;
|
|
|
+
|
|
|
+ ::v-deep .el-tabs--border-card {
|
|
|
+ box-shadow: none;
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
+ height: 100%;
|
|
|
+
|
|
|
+ .el-tabs__header {
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
+ margin: 0;
|
|
|
+
|
|
|
+ .el-tabs__nav {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-tabs__item {
|
|
|
+ flex: 1;
|
|
|
+ height: 39px;
|
|
|
+ line-height: 39px;
|
|
|
+ font-size: 13px;
|
|
|
+ padding: 0;
|
|
|
+ text-align: center;
|
|
|
+
|
|
|
+ &.is-active {
|
|
|
+ background-color: #fff;
|
|
|
+ border-bottom-color: #fff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-tabs__content {
|
|
|
+ padding: 10px;
|
|
|
+ height: calc(100% - 40px);
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-tree {
|
|
|
+ padding: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.card-mode {
|
|
|
+ ::v-deep .el-tabs--border-card {
|
|
|
+ background: linear-gradient(135deg, #151825 0%, #1a1c2e 100%);
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.08);
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
|
+
|
|
|
+ .el-tabs__header {
|
|
|
+ background: rgba(255, 255, 255, 0.05);
|
|
|
+ border-bottom-color: rgba(255, 255, 255, 0.1);
|
|
|
+
|
|
|
+ .el-tabs__item {
|
|
|
+ color: rgba(255, 255, 255, 0.6);
|
|
|
+ border-right-color: rgba(255, 255, 255, 0.1);
|
|
|
+
|
|
|
+ &.is-active {
|
|
|
+ background: rgba(255, 255, 255, 0.1);
|
|
|
+ color: #409eff;
|
|
|
+ border-bottom-color: transparent;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: rgba(255, 255, 255, 0.8);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-tabs__content {
|
|
|
+ background: transparent;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-tree {
|
|
|
+ color: rgba(255, 255, 255, 0.8);
|
|
|
+
|
|
|
+ .el-tree-node__content {
|
|
|
+ background: transparent;
|
|
|
+ color: rgba(255, 255, 255, 0.8);
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: rgba(64, 158, 255, 0.1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-tree-node__label {
|
|
|
+ color: rgba(255, 255, 255, 0.8);
|
|
|
+ }
|
|
|
+
|
|
|
+ .is-current > .el-tree-node__content {
|
|
|
+ background: rgba(64, 158, 255, 0.2);
|
|
|
+ color: #409eff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .right-content {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ padding-left: 15px;
|
|
|
+
|
|
|
+ &.card-mode {
|
|
|
+ background: transparent;
|
|
|
+ }
|
|
|
+
|
|
|
+ .search-area {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ padding-bottom: 10px;
|
|
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
+
|
|
|
+ .status-tabs {
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .search-input-wrapper {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .view-switch {
|
|
|
+ margin-left: 20px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.card-mode {
|
|
|
+ background: linear-gradient(135deg, #151825 0%, #1a1c2e 100%);
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 15px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.08);
|
|
|
+
|
|
|
+ ::v-deep .el-radio-button__inner {
|
|
|
+ background: rgba(255, 255, 255, 0.08) !important;
|
|
|
+ border-color: rgba(255, 255, 255, 0.2) !important;
|
|
|
+ color: rgba(255, 255, 255, 0.8) !important;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: #409eff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep
|
|
|
+ .el-radio-button__orig-radio:checked
|
|
|
+ + .el-radio-button__inner {
|
|
|
+ background-color: #409eff !important;
|
|
|
+ border-color: #409eff !important;
|
|
|
+ color: #fff !important;
|
|
|
+ box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-input__inner {
|
|
|
+ background: rgba(255, 255, 255, 0.08) !important;
|
|
|
+ border-color: rgba(255, 255, 255, 0.2) !important;
|
|
|
+ color: rgba(255, 255, 255, 0.8) !important;
|
|
|
+
|
|
|
+ &::-webkit-input-placeholder {
|
|
|
+ color: rgba(255, 255, 255, 0.4);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-input__icon {
|
|
|
+ color: rgba(255, 255, 255, 0.5);
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-button--default {
|
|
|
+ background: rgba(255, 255, 255, 0.08);
|
|
|
+ border-color: rgba(255, 255, 255, 0.2);
|
|
|
+ color: rgba(255, 255, 255, 0.8);
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: rgba(255, 255, 255, 0.15);
|
|
|
+ color: #409eff;
|
|
|
+ border-color: rgba(64, 158, 255, 0.4);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-button--primary {
|
|
|
+ background: #409eff;
|
|
|
+ border-color: #409eff;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: #66b1ff;
|
|
|
+ border-color: #66b1ff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .update-time {
|
|
|
+ background: linear-gradient(135deg, #151825 0%, #1a1c2e 100%);
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 12px 15px;
|
|
|
+ color: rgba(255, 255, 255, 0.6);
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.08);
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .card-view {
|
|
|
+ background: transparent;
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 15px;
|
|
|
+ height: calc(100vh - 320px);
|
|
|
+ overflow-y: auto;
|
|
|
+ padding-right: 10px;
|
|
|
+
|
|
|
+ .device-card {
|
|
|
+ height: 160px;
|
|
|
+ background: linear-gradient(
|
|
|
+ 145deg,
|
|
|
+ rgba(30, 34, 50, 0.9) 0%,
|
|
|
+ rgba(20, 23, 35, 0.95) 100%
|
|
|
+ );
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.12);
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 20px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s;
|
|
|
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4),
|
|
|
+ inset 0 1px 0 rgba(255, 255, 255, 0.05);
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ box-shadow: 0 12px 28px rgba(0, 0, 0, 0.5),
|
|
|
+ 0 0 0 1px rgba(64, 158, 255, 0.3);
|
|
|
+ transform: translateY(-4px);
|
|
|
+ border-color: rgba(64, 158, 255, 0.5);
|
|
|
+ background: linear-gradient(
|
|
|
+ 145deg,
|
|
|
+ rgba(35, 40, 55, 0.95) 0%,
|
|
|
+ rgba(25, 28, 40, 0.98) 100%
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ &.is-fault {
|
|
|
+ background: linear-gradient(
|
|
|
+ 145deg,
|
|
|
+ rgba(255, 107, 107, 0.15) 0%,
|
|
|
+ rgba(255, 107, 107, 0.08) 100%
|
|
|
+ );
|
|
|
+ border-color: rgba(255, 107, 107, 0.6);
|
|
|
+ }
|
|
|
+
|
|
|
+ .card-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ padding-bottom: 12px;
|
|
|
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
|
+
|
|
|
+ .device-name {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: rgba(255, 255, 255, 0.9);
|
|
|
+ flex: 1;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ .card-actions {
|
|
|
+ .alarm-icon {
|
|
|
+ font-size: 18px;
|
|
|
+ color: rgba(255, 255, 255, 0.4);
|
|
|
+
|
|
|
+ &.has-alarm {
|
|
|
+ color: #ff6b6b;
|
|
|
+ animation: bellshake 2s infinite;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .card-body {
|
|
|
+ .status-tag {
|
|
|
+ margin-bottom: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .info-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 1fr 1fr;
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ .info-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 0;
|
|
|
+
|
|
|
+ .info-label {
|
|
|
+ font-size: 12px;
|
|
|
+ color: rgba(255, 255, 255, 0.5);
|
|
|
+ min-width: 60px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .info-value {
|
|
|
+ font-size: 12px;
|
|
|
+ color: rgba(255, 255, 255, 0.7);
|
|
|
+ flex: 1;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ margin-left: 5px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .pagination-area {
|
|
|
+ margin-top: 15px;
|
|
|
+ padding: 15px 0;
|
|
|
+
|
|
|
+ ::v-deep .el-pagination {
|
|
|
+ justify-content: flex-end;
|
|
|
+
|
|
|
+ .el-pagination__total {
|
|
|
+ margin-right: 16px;
|
|
|
+ color: rgba(255, 255, 255, 0.6);
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-pagination__sizes {
|
|
|
+ margin-right: 16px;
|
|
|
+
|
|
|
+ .el-select .el-input .el-input__inner {
|
|
|
+ background: rgba(255, 255, 255, 0.1);
|
|
|
+ border-color: rgba(255, 255, 255, 0.2);
|
|
|
+ color: rgba(255, 255, 255, 0.8);
|
|
|
+
|
|
|
+ &::-webkit-input-placeholder {
|
|
|
+ color: rgba(255, 255, 255, 0.4);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-select-dropdown {
|
|
|
+ background: #1a1c2e;
|
|
|
+ border-color: rgba(255, 255, 255, 0.2);
|
|
|
+
|
|
|
+ .el-select-dropdown__item {
|
|
|
+ color: rgba(255, 255, 255, 0.8);
|
|
|
+
|
|
|
+ &:hover,
|
|
|
+ &.selected {
|
|
|
+ background: rgba(64, 158, 255, 0.2);
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-pager {
|
|
|
+ margin: 0 4px;
|
|
|
+
|
|
|
+ li {
|
|
|
+ margin: 0 4px;
|
|
|
+ border-radius: 50%;
|
|
|
+ min-width: 28px;
|
|
|
+ height: 28px;
|
|
|
+ line-height: 28px;
|
|
|
+ background: rgba(255, 255, 255, 0.05);
|
|
|
+ color: rgba(255, 255, 255, 0.6);
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ background-color: #409eff;
|
|
|
+ color: #fff !important;
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: #409eff;
|
|
|
+ background: rgba(255, 255, 255, 0.1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-prev,
|
|
|
+ .btn-next {
|
|
|
+ border-radius: 50%;
|
|
|
+ min-width: 28px;
|
|
|
+ height: 28px;
|
|
|
+ line-height: 28px;
|
|
|
+ padding: 0;
|
|
|
+ background: rgba(255, 255, 255, 0.05);
|
|
|
+ color: rgba(255, 255, 255, 0.6);
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: #409eff;
|
|
|
+ background: rgba(255, 255, 255, 0.1);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.disabled {
|
|
|
+ background: rgba(255, 255, 255, 0.02);
|
|
|
+ color: rgba(255, 255, 255, 0.2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-pagination__jump {
|
|
|
+ margin-left: 16px;
|
|
|
+ color: rgba(255, 255, 255, 0.6);
|
|
|
+
|
|
|
+ input {
|
|
|
+ background: rgba(255, 255, 255, 0.1);
|
|
|
+ border-color: rgba(255, 255, 255, 0.2);
|
|
|
+ color: rgba(255, 255, 255, 0.8);
|
|
|
+
|
|
|
+ &::-webkit-input-placeholder {
|
|
|
+ color: rgba(255, 255, 255, 0.4);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-pagination {
|
|
|
+ justify-content: flex-end;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @keyframes bellshake {
|
|
|
+ 0%,
|
|
|
+ 100% {
|
|
|
+ transform: rotate(0deg);
|
|
|
+ }
|
|
|
+ 10%,
|
|
|
+ 30%,
|
|
|
+ 50%,
|
|
|
+ 70%,
|
|
|
+ 90% {
|
|
|
+ transform: rotate(-10deg);
|
|
|
+ }
|
|
|
+ 20%,
|
|
|
+ 40%,
|
|
|
+ 60%,
|
|
|
+ 80% {
|
|
|
+ transform: rotate(10deg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|