Ver código fonte

feat: 添加设备运行监控仪表盘功能

yusheng 2 meses atrás
pai
commit
e21ca0da38

+ 9 - 1
src/api/ledgerAssets/equipment.js

@@ -36,4 +36,12 @@ export async function getPhysicalModel(id) {
     return res.data.data;
   }
   return Promise.reject(new Error(res.data.message));
-}
+}
+// 保存仪表盘配置
+export async function updateIotDashboardPosition(data) {
+  const res = await request.post(`main/asset/updateIotDashboardPosition`, data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}

+ 9 - 1
src/api/ledgerAssets/index.js

@@ -40,6 +40,15 @@ export async function getAssetList(data) {
   }
   return Promise.reject(new Error(res.data.message));
 }
+// 获取仪表列表分页
+export async function querySubstanceRunningMonitor(data) {
+  let par = new URLSearchParams(data);
+  const res = await request.get(`/main/asset/querySubstanceRunningMonitor?` + par, {});
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
 
 // 查询实例详情
 export async function getAssetInfo(id) {
@@ -174,4 +183,3 @@ export async function batchUnbind(data) {
   }
   return Promise.reject(new Error(res.data.message));
 }
-

+ 6 - 6
src/public-path.js

@@ -1,11 +1,11 @@
 (function () {
   if (window.__POWERED_BY_QIANKUN__) {
-    if (process.env.NODE_ENV === 'development') {
-      // eslint-disable-next-line
-      __webpack_public_path__ = `//localhost:${process.env.VUE_APP_PORT}/`;
-      console.log('__webpack_public_path__', __webpack_public_path__);
-      return;
-    }
+    // if (process.env.NODE_ENV === 'development') {
+    //   // eslint-disable-next-line
+    //   __webpack_public_path__ = `//localhost:${process.env.VUE_APP_PORT}/`;
+    //   console.log('__webpack_public_path__', __webpack_public_path__);
+    //   return;
+    // }
     // eslint-disable-next-line
     __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
     // __webpack_public_path__ = `${process.env.BASE_URL}/`

+ 908 - 206
src/views/equipmentOperationMonitoring/index.vue

@@ -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>

+ 1 - 0
src/views/ledgerAssets/components/details/components/GaugeChart.vue

@@ -378,6 +378,7 @@ export default {
      * @public
      */
     redraw() {
+   
       if (!this.chartInstance) {
         this.initChart();
       } else {

Diferenças do arquivo suprimidas por serem muito extensas
+ 584 - 389
src/views/ledgerAssets/components/details/components/internetDetail.vue


+ 30 - 8
src/views/ledgerAssets/components/details/internet.vue

@@ -4,7 +4,14 @@
     <div class="basic-details" id="internet">
       <div class="basic-details-title">
         <span class="border-span">物联数据</span>
-        <el-button v-if="isIotEnable == 1" type="primary" @click="updateInfo">更新</el-button>
+        <div
+          ><el-button v-if="isIotEnable == 1" type="primary" @click="updateInfo"
+            >更新</el-button
+          >
+          <el-button v-if="isIotEnable == 1" type="primary" @click="edit"
+            >点位配置</el-button
+          ></div
+        >
       </div>
     </div>
     <div class="basic-details-name">{{ name }}</div>
@@ -14,7 +21,13 @@
     <!-- <InternetDryingBox :info="info" v-else-if="parentClassId == '57'" /> -->
     <!-- 其他设备 -->
     <!-- <InternetOther v-else :id="id"></InternetOther> -->
-     <internetDetail ref="internetDetailRef" :info="info" :id="id"></internetDetail>
+    <internetDetail
+      ref="internetDetailRef"
+      :info="info"
+      :id="id"
+      :iotDashboardPoint="iotDashboardPoint"
+      @success="getInfo"
+    ></internetDetail>
   </div>
 </template>
 
@@ -27,7 +40,12 @@
   import { getAssetInfo } from '@/api/ledgerAssets';
   export default {
     props: ['id', 'name'],
-    components: { InternetExtruder, InternetDryingBox, InternetOther, internetDetail },
+    components: {
+      InternetExtruder,
+      InternetDryingBox,
+      InternetOther,
+      internetDetail
+    },
 
     data() {
       return {
@@ -38,7 +56,8 @@
         // name: '',
         // 父类id
         parentClassId: '65',
-        isIotEnable: null
+        isIotEnable: null,
+        iotDashboardPoint:[]
       };
     },
     created() {
@@ -48,13 +67,12 @@
       async getInfo() {
         const data = await getAssetInfo(this.id);
         this.isIotEnable = data.isIotEnable;
+        this.iotDashboardPoint=data.iotDashboardPoint
         console.log('data~~~~~', data);
-        if(data.isIotEnable != 1) {
+        if (data.isIotEnable != 1) {
           return this.$message.error('该设备未启用物联。');
         }
-        getDetail(
-          this.id
-        ).then((res) => {
+        getDetail(this.id).then((res) => {
           this.info = res;
           console.log(this.info);
           // this.parentClassId = this.setParentClassId(
@@ -62,11 +80,15 @@
           // );
         });
       },
+
       // 获取父类id
       setParentClassId(val) {
         let data = JSON.parse(val);
         return data[1];
       },
+      edit() {
+        this.$refs.internetDetailRef.edit();
+      },
       // 更新信息
       updateInfo() {
         this.$refs.internetDetailRef.getRealData();

+ 1 - 0
src/views/ledgerAssets/equipment/detail.vue

@@ -91,6 +91,7 @@
       this.id = this.$route.query.id;
       this.code = this.$route.query.code;
       this.name = this.$route.query.name;
+      this.activeComp=this.$route.query.activeComp||'baseInfo';
       console.log('routerouterouteroute', this.$route);
     }
   };

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff