|
@@ -1,1261 +1,1058 @@
|
|
|
<template>
|
|
|
<div class="app-container">
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="4" :xs="24">
|
|
|
- <div class="head-container">
|
|
|
- <el-input v-model="areaName" placeholder="请输入区域名称" clearable size="small" prefix-icon="el-icon-search"
|
|
|
- style="margin-bottom: 20px"
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div class="head-container" style="height: 100vh; overflow: hidden; position: relative;">
|
|
|
- <el-tree :data="treeAreaOptions" :props="defaultProps" :expand-on-click-node="false"
|
|
|
- :filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current
|
|
|
- @node-click="handleNodeClick" style="height: calc(100vh - 50px); overflow-y: auto;"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="20" :xs="24">
|
|
|
- <div class="contents">
|
|
|
- <div class="other-content">
|
|
|
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
|
|
|
- label-width="68px"
|
|
|
- >
|
|
|
- <el-form-item label="设备分类" prop="deviceSubCategory">
|
|
|
- <el-select v-model="queryParams.deviceSubCategory">
|
|
|
- <el-option v-for="item in subCategoryOptions" placeholder="设备分类" :label="item.name"
|
|
|
- :value="item.code"
|
|
|
- :key="item.code"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
+ <!-- 系统基础信息卡片 -->
|
|
|
+ <el-card class="system-info-card">
|
|
|
+ <div slot="header" class="card-header">
|
|
|
+ <span class="title">
|
|
|
+ <i class="el-icon-s-platform"></i>
|
|
|
+ 能耗监测
|
|
|
+ </span>
|
|
|
+ <el-tag :type="systemStatus === '1' ? 'success' : 'danger'" effect="dark">
|
|
|
+ {{ systemStatus === '1' ? '正常' : '异常' }}
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="8">
|
|
|
+ <div class="info-group">
|
|
|
+ <div class="group-title">系统信息</div>
|
|
|
+ <div class="info-item">
|
|
|
+ <label>系统代码:</label>
|
|
|
+ <span class="code">{{ systemInfo.systemCode }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="info-item">
|
|
|
+ <label>系统名称:</label>
|
|
|
+ <span>{{ systemInfo.systemName }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <div class="info-group">
|
|
|
+ <div class="group-title">厂商信息</div>
|
|
|
+ <div class="info-item">
|
|
|
+ <label>对接厂商:</label>
|
|
|
+ <span>{{ systemInfo.manFacturer || '-' }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="info-item">
|
|
|
+ <label>联系人:</label>
|
|
|
+ <span>{{ systemInfo.contactPerson || '-' }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="info-item">
|
|
|
+ <label>联系电话:</label>
|
|
|
+ <span>{{ systemInfo.contactNumber || '-' }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <div class="info-group">
|
|
|
+ <div class="group-title">维护信息</div>
|
|
|
+ <div class="info-item">
|
|
|
+ <label>维护人:</label>
|
|
|
+ <span>{{ systemInfo.maintainerPerson || '-' }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="info-item">
|
|
|
+ <label>维护电话:</label>
|
|
|
+ <span>{{ systemInfo.maintainerNumber || '-' }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 系统详情标签页 -->
|
|
|
+ <el-card class="detail-card">
|
|
|
+ <el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
|
|
+ <!-- 系统属性标签页 -->
|
|
|
+ <el-tab-pane label="系统属性" name="attributes">
|
|
|
+ <div class="tab-content">
|
|
|
+ <!-- 协议属性 -->
|
|
|
+ <div class="attr-section" v-if="protocolAttrs.length > 0">
|
|
|
+ <h4 class="section-title">
|
|
|
+ <i class="el-icon-connection"></i>
|
|
|
+ 协议信息
|
|
|
+ </h4>
|
|
|
+ <el-table :data="protocolAttrs" border stripe>
|
|
|
+ <el-table-column prop="attrName" label="属性名称" width="200"></el-table-column>
|
|
|
+ <el-table-column label="属性值">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span v-if="scope.row.attrKey === 'url'" class="url-text">
|
|
|
+ {{ scope.row.attrValue }}
|
|
|
+ </span>
|
|
|
+ <span v-else>{{ scope.row.attrValue || '-' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 状态属性 -->
|
|
|
+ <div class="attr-section" v-if="stateAttrs.length > 0">
|
|
|
+ <h4 class="section-title">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ 状态信息
|
|
|
+ </h4>
|
|
|
+ <el-table :data="stateAttrs" border stripe>
|
|
|
+ <el-table-column prop="attrName" label="属性名称" width="200"></el-table-column>
|
|
|
+ <el-table-column label="属性值">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag v-if="scope.row.attrKey === 'interfaceStatus'"
|
|
|
+ :type="scope.row.attrValue === '1' ? 'success' : 'danger'">
|
|
|
+ {{ scope.row.attrValueName }}
|
|
|
+ </el-tag>
|
|
|
+ <span v-else>{{ scope.row.attrValueName || scope.row.attrValue || '-' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="updateTime" label="更新时间" width="180"></el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <!-- 系统能力标签页 -->
|
|
|
+ <el-tab-pane label="系统能力" name="abilities">
|
|
|
+ <div class="tab-content">
|
|
|
+ <el-table :data="systemAbilities" border stripe v-loading="abilityLoading">
|
|
|
+ <el-table-column prop="abilityName" label="能力名称" width="200"></el-table-column>
|
|
|
+ <el-table-column prop="abilityKey" label="能力标识" width="180"></el-table-column>
|
|
|
+ <el-table-column prop="abilityDesc" label="能力描述"></el-table-column>
|
|
|
+ <el-table-column label="操作" width="150" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ size="mini"
|
|
|
+ icon="el-icon-caret-right"
|
|
|
+ @click="executeAbility(scope.row)"
|
|
|
+ :loading="scope.row.executing">
|
|
|
+ 执行
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <!-- 关联设备标签页 -->
|
|
|
+ <el-tab-pane label="关联设备" name="devices">
|
|
|
+ <div class="tab-content">
|
|
|
+ <!-- 设备统计 -->
|
|
|
+ <div class="device-stats">
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="6">
|
|
|
+ <div class="stat-item">
|
|
|
+ <div class="stat-value">{{ deviceStats.total }}</div>
|
|
|
+ <div class="stat-label">设备总数</div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <div class="stat-item online">
|
|
|
+ <div class="stat-value">{{ deviceStats.online }}</div>
|
|
|
+ <div class="stat-label">在线设备</div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <div class="stat-item offline">
|
|
|
+ <div class="stat-value">{{ deviceStats.offline }}</div>
|
|
|
+ <div class="stat-label">离线设备</div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <div class="stat-item">
|
|
|
+ <div class="stat-value">{{ deviceStats.points }}</div>
|
|
|
+ <div class="stat-label">测点总数</div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 设备列表 -->
|
|
|
+ <el-table
|
|
|
+ :data="deviceList"
|
|
|
+ border
|
|
|
+ stripe
|
|
|
+ v-loading="deviceLoading"
|
|
|
+ @row-click="handleDeviceClick"
|
|
|
+ ref="deviceTable">
|
|
|
+ <el-table-column type="expand">
|
|
|
+ <template slot-scope="props">
|
|
|
+ <div class="device-detail">
|
|
|
+ <el-tabs v-model="props.row.detailTab">
|
|
|
+ <el-tab-pane label="设备属性" name="attrs">
|
|
|
+ <el-descriptions :column="2" border size="small">
|
|
|
+ <el-descriptions-item label="IP地址">
|
|
|
+ {{ getDeviceAttr(props.row.deviceCode, 'ip') }}
|
|
|
+ </el-descriptions-item>
|
|
|
+ <el-descriptions-item label="网关地址">
|
|
|
+ {{ getDeviceAttr(props.row.deviceCode, 'gateway') }}
|
|
|
+ </el-descriptions-item>
|
|
|
+ <el-descriptions-item label="子网掩码">
|
|
|
+ {{ getDeviceAttr(props.row.deviceCode, 'subnetMask') }}
|
|
|
+ </el-descriptions-item>
|
|
|
+ </el-descriptions>
|
|
|
+ </el-tab-pane>
|
|
|
+ <el-tab-pane label="测点信息" name="points">
|
|
|
+ <div v-for="(channel, idx) in getDeviceChannels(props.row.deviceCode)" :key="idx">
|
|
|
+ <h5>{{ channel.name }} ({{ channel.points.length }}个测点)</h5>
|
|
|
+ <el-table :data="channel.points" size="mini" max-height="200">
|
|
|
+ <el-table-column prop="name" label="测点名称"></el-table-column>
|
|
|
+ <el-table-column prop="key" label="测点标识"></el-table-column>
|
|
|
+ <el-table-column prop="value" label="当前值">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ {{ scope.row.value || '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="updateTime" label="更新时间"></el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="deviceCode" label="设备代码" width="150"></el-table-column>
|
|
|
+ <el-table-column prop="deviceName" label="设备名称"></el-table-column>
|
|
|
+ <el-table-column prop="location" label="安装位置"></el-table-column>
|
|
|
+ <el-table-column prop="areaCode" label="区域" width="150">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ {{ scope.row.areaCode.includes('3001') ? '北区' : '南区' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="设备状态" width="100" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag :type="scope.row.deviceStatus === 1 ? 'success' : 'info'">
|
|
|
+ {{ scope.row.deviceStatus === 1 ? '在线' : '离线' }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="100" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-dropdown
|
|
|
+ trigger="click"
|
|
|
+ @command="handleDeviceCommand"
|
|
|
+ @visible-change="(visible) => handleAbilityLoad(visible, scope.row)">
|
|
|
+ <el-button type="text" size="mini">
|
|
|
+ 操作<i class="el-icon-arrow-down el-icon--right"></i>
|
|
|
+ </el-button>
|
|
|
+ <el-dropdown-menu slot="dropdown">
|
|
|
+ <el-dropdown-item
|
|
|
+ v-for="ability in deviceAbilities[scope.row.deviceCode] || []"
|
|
|
+ :key="ability.abilityKey"
|
|
|
+ :command="{device: scope.row, ability: ability}">
|
|
|
+ {{ ability.abilityName }}
|
|
|
+ </el-dropdown-item>
|
|
|
+ <el-dropdown-item
|
|
|
+ v-if="!deviceAbilities[scope.row.deviceCode] || deviceAbilities[scope.row.deviceCode].length === 0"
|
|
|
+ disabled>
|
|
|
+ 无可用操作
|
|
|
+ </el-dropdown-item>
|
|
|
+ </el-dropdown-menu>
|
|
|
+ </el-dropdown>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <!-- 调用日志标签页 -->
|
|
|
+ <el-tab-pane label="调用日志" name="callLogs">
|
|
|
+ <div class="tab-content">
|
|
|
+ <el-form :inline="true" :model="callLogQuery" class="log-filter">
|
|
|
+ <el-form-item label="时间范围">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="callLogQuery.dateRange"
|
|
|
+ type="datetimerange"
|
|
|
+ range-separator="至"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ value-format="yyyy-MM-dd HH:mm:ss">
|
|
|
+ </el-date-picker>
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="归属设施" prop="refFacs">
|
|
|
- <el-select v-model="queryParams.refFacs">
|
|
|
- <el-option v-for="item in facsOptions" :label="item.facsName" :value="item.facsCode"
|
|
|
- :key="item.facsCode"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
+ <el-form-item label="能力标识">
|
|
|
+ <el-input v-model="callLogQuery.abilityKey" placeholder="请输入能力标识" clearable></el-input>
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="子系统" prop="subsystemCode">
|
|
|
- <el-select v-model="queryParams.subsystemCode">
|
|
|
- <el-option v-for="item in subsystemOptions" :label="item.systemName" :value="item.systemCode"
|
|
|
- :key="item.systemCode"
|
|
|
- />
|
|
|
+ <el-form-item label="调用状态">
|
|
|
+ <el-select v-model="callLogQuery.callStatus" placeholder="全部" clearable>
|
|
|
+ <el-option label="成功" :value="0"></el-option>
|
|
|
+ <el-option label="进行中" :value="1"></el-option>
|
|
|
+ <el-option label="失败" :value="2"></el-option>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item>
|
|
|
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
|
|
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
|
|
+ <el-button type="primary" @click="queryCallLogs">查询</el-button>
|
|
|
+ <el-button @click="resetCallLogQuery">重置</el-button>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
|
|
|
- <el-row :gutter="10" class="mb8">
|
|
|
- <el-col :span="1.5">
|
|
|
- <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
|
|
|
- v-hasPermi="['ems:device:add']"
|
|
|
- >新增
|
|
|
- </el-button>
|
|
|
- </el-col>
|
|
|
- <el-col :span="1.5">
|
|
|
- <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
|
|
|
- v-hasPermi="['ems:device:edit']"
|
|
|
- >修改
|
|
|
- </el-button>
|
|
|
- </el-col>
|
|
|
- <el-col :span="1.5">
|
|
|
- <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
|
|
|
- @click="handleDelete"
|
|
|
- v-hasPermi="['ems:device:remove']"
|
|
|
- >删除
|
|
|
- </el-button>
|
|
|
- </el-col>
|
|
|
- <el-col :span="1.5">
|
|
|
- <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
|
|
|
- v-hasPermi="['ems:device:export']"
|
|
|
- >导出
|
|
|
- </el-button>
|
|
|
- </el-col>
|
|
|
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="table-content">
|
|
|
- <!--分页-->
|
|
|
- <div class="button-group-container">
|
|
|
- <el-button-group>
|
|
|
- <el-button :type="primary1" icon="el-icon-s-fold" @click="switchData(1)"/>
|
|
|
- <el-button :type="primary2" icon="el-icon-menu" @click="switchData(2)"/>
|
|
|
- </el-button-group>
|
|
|
- </div>
|
|
|
-
|
|
|
- <el-table v-loading="loading" :data="deviceList" @selection-change="handleSelectionChange"
|
|
|
- v-if="istable === 1">
|
|
|
- <el-table-column type="selection" width="55" align="center"/>
|
|
|
- <el-table-column label="设备名称" align="left" prop="deviceName"/>
|
|
|
- <el-table-column label="安装位置" align="left" prop="areaPath" width="220px"/>
|
|
|
- <el-table-column label="归属设施" align="center" prop="refFacsName"/>
|
|
|
- <el-table-column label="设备分类" align="center" prop="deviceCategoryName"/>
|
|
|
- <el-table-column label="子系统" align="center" prop="subsystemName"/>
|
|
|
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
|
|
+ <el-table :data="callLogList" border stripe v-loading="logLoading">
|
|
|
+ <el-table-column prop="objCode" label="对象代码" min-width="150"></el-table-column>
|
|
|
+ <el-table-column prop="objName" label="对象名称" min-width="200"></el-table-column>
|
|
|
+ <el-table-column prop="abilityName" label="能力名称" min-width="150"></el-table-column>
|
|
|
+ <el-table-column prop="callTime" label="调用时间" width="180"></el-table-column>
|
|
|
+ <el-table-column label="调用状态" width="100" align="center">
|
|
|
<template slot-scope="scope">
|
|
|
- <el-button size="mini" type="text" icon="el-icon-info" @click="handleDevProcess(scope.row)"
|
|
|
- v-hasPermi="['basecfg:device:edit']" v-if="shouldShowDevProcessButton(scope.row)"
|
|
|
- >
|
|
|
- 器件
|
|
|
- </el-button>
|
|
|
- <el-button size="mini" type="text" icon="el-icon-info" @click="handleDetail(scope.row)"
|
|
|
- v-hasPermi="['basecfg:device:edit']"
|
|
|
- >
|
|
|
- 详情
|
|
|
- </el-button>
|
|
|
- <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
|
|
- v-hasPermi="['basecfg:device:edit']"
|
|
|
- >
|
|
|
- 修改
|
|
|
- </el-button>
|
|
|
- <el-button size="mini" type="text" icon="el-icon-delete" class="deleteBtn"
|
|
|
- @click="handleDelete(scope.row)" v-hasPermi="['basecfg:device:remove']"
|
|
|
- >
|
|
|
- 删除
|
|
|
- </el-button>
|
|
|
-
|
|
|
+ <el-tag size="small" :type="getCallStatusType(scope.row.callStatus)">
|
|
|
+ {{ formatCallStatus(scope.row.callStatus) }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="80" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-button type="text" size="mini" @click="handleCallLogDetail(scope.row)">详情</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
|
|
|
- <div v-else-if="istable === 2">
|
|
|
- <el-row :gutter="20" class="device-list">
|
|
|
- <el-col v-for="device in deviceList" :key="device.id" :span="6">
|
|
|
- <div :class="`device-card ${backStyle(device.areaPath)}`">
|
|
|
- <div class="device-header">
|
|
|
- <i class="el-icon-s-operation" style="margin-right: 8px;"></i>
|
|
|
- {{ device.deviceName }}
|
|
|
- </div>
|
|
|
- <div class="device-body">
|
|
|
- <p>设备代码:<span class="device-code">{{ device.deviceCode }}</span></p>
|
|
|
- <p>安装位置:<span class="deviceOthers">{{ device.areaPath }}</span></p>
|
|
|
- <p>归属设施:<span class="deviceOthers">{{ device.refFacsName }}</span></p>
|
|
|
- <p>设备分类:<span class="deviceOthers">{{ device.deviceCategoryName }}</span></p>
|
|
|
- <p>子系统:<span class="deviceOthers">{{ device.subsystemName }}</span></p>
|
|
|
- </div>
|
|
|
- <div class="device-footer">
|
|
|
- <el-button size="mini" plain icon=" el-icon-document" @click="handleDetail(device)">详情
|
|
|
- </el-button>
|
|
|
- <el-button size="mini" plain icon="el-icon-edit" @click="handleUpdate(device)">修改</el-button>
|
|
|
- <el-button size="mini" plain icon="el-icon-delete" type="danger" @click="handleDelete(device)">
|
|
|
- 删除
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
+ <pagination
|
|
|
+ v-show="callLogTotal > 0"
|
|
|
+ :total="callLogTotal"
|
|
|
+ :page.sync="callLogQuery.pageNum"
|
|
|
+ :limit.sync="callLogQuery.pageSize"
|
|
|
+ @pagination="queryCallLogs"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <!-- 事件日志标签页 -->
|
|
|
+ <el-tab-pane label="事件日志" name="eventLogs">
|
|
|
+ <div class="tab-content">
|
|
|
+ <el-form :inline="true" :model="eventLogQuery" class="log-filter">
|
|
|
+ <el-form-item label="时间范围">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="eventLogQuery.dateRange"
|
|
|
+ type="datetimerange"
|
|
|
+ range-separator="至"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ value-format="yyyy-MM-dd HH:mm:ss">
|
|
|
+ </el-date-picker>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="事件标识">
|
|
|
+ <el-input v-model="eventLogQuery.eventKey" placeholder="请输入事件标识" clearable></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" @click="queryEventLogs">查询</el-button>
|
|
|
+ <el-button @click="resetEventLogQuery">重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
|
|
|
+ <el-table :data="eventLogList" border stripe v-loading="eventLogLoading">
|
|
|
+ <el-table-column prop="objCode" label="对象编号" min-width="150"></el-table-column>
|
|
|
+ <el-table-column prop="objName" label="对象名称" min-width="200"></el-table-column>
|
|
|
+ <el-table-column prop="eventName" label="事件名称" min-width="200"></el-table-column>
|
|
|
+ <el-table-column prop="eventTime" label="事件时间" width="180"></el-table-column>
|
|
|
+ <el-table-column label="操作" width="80" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-button type="text" size="mini" @click="handleEventLogDetail(scope.row)">详情</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
|
|
|
- <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
|
|
|
- :limit.sync="queryParams.pageSize"
|
|
|
- @pagination="getList"
|
|
|
+ <pagination
|
|
|
+ v-show="eventLogTotal > 0"
|
|
|
+ :total="eventLogTotal"
|
|
|
+ :page.sync="eventLogQuery.pageNum"
|
|
|
+ :limit.sync="eventLogQuery.pageSize"
|
|
|
+ @pagination="queryEventLogs"
|
|
|
/>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 执行结果对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ :title="executeDialog.title"
|
|
|
+ :visible.sync="executeDialog.visible"
|
|
|
+ width="600px">
|
|
|
+ <div class="execute-result">
|
|
|
+ <el-alert
|
|
|
+ :title="executeDialog.status"
|
|
|
+ :type="executeDialog.type"
|
|
|
+ :description="executeDialog.message"
|
|
|
+ show-icon>
|
|
|
+ </el-alert>
|
|
|
+ <div v-if="executeDialog.data" class="result-data">
|
|
|
+ <pre>{{ JSON.stringify(executeDialog.data, null, 2) }}</pre>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <span slot="footer">
|
|
|
+ <el-button @click="executeDialog.visible = false">关闭</el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 调用日志详情弹窗 -->
|
|
|
+ <el-dialog :visible.sync="callLogDetailDialog" title="调用日志详情" width="60%">
|
|
|
+ <div v-if="callLogDetailData">
|
|
|
+ <el-descriptions :column="2" border>
|
|
|
+ <el-descriptions-item label="对象代码">{{ callLogDetailData.objCode }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="模型代码">{{ callLogDetailData.modelCode }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="能力标识">{{ callLogDetailData.abilityKey }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="调用时间">{{ callLogDetailData.callTime }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="响应时间">{{ callLogDetailData.resTime }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="调用结果">
|
|
|
+ <el-tag :type="getCallStatusType(callLogDetailData.callStatus)">
|
|
|
+ {{ formatCallStatus(callLogDetailData.callStatus) }}
|
|
|
+ </el-tag>
|
|
|
+ </el-descriptions-item>
|
|
|
+ </el-descriptions>
|
|
|
+
|
|
|
+ <div style="margin-top: 20px;">
|
|
|
+ <h4>调用载体</h4>
|
|
|
+ <pre style="white-space: pre-wrap; background-color: #f5f5f5; padding: 10px; border-radius: 4px; max-height: 300px; overflow: auto;">{{ callLogDetailData.callPayload }}</pre>
|
|
|
+ </div>
|
|
|
|
|
|
- <!-- 添加或修改能源设备对话框 -->
|
|
|
- <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
|
|
- <el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
|
|
- <el-form-item label="归属设施" prop="refFacs">
|
|
|
- <el-select v-model="form.refFacs">
|
|
|
- <el-option v-for="item in facsOptions" :label="item.facsName" :value="item.facsCode"
|
|
|
- :key="item.facsCode"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="设备代码" prop="deviceCode">
|
|
|
- <el-input v-model="form.deviceCode" placeholder="请输入设备代码"/>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="设备名称" prop="deviceName">
|
|
|
- <el-input v-model="form.deviceName" placeholder="请输入设备名称"/>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
-
|
|
|
- <el-form-item label="功能类型" prop="psCode" v-if="queryParams.deviceCategory === 'W'">
|
|
|
- <el-select v-model="form.psCode">
|
|
|
- <el-option v-for="item in devOptions" :label="item.psName" :value="item.psCode"
|
|
|
- :key="item.psCode"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="设备类型" prop="deviceType">
|
|
|
- <el-select v-model="form.deviceCategory">
|
|
|
- <el-option v-for="item in subCategoryOptions" :label="item.name" :value="item.code"
|
|
|
- :key="item.code"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="设备模型" prop="deviceModel">
|
|
|
- <el-select v-model="form.deviceModel" style="width:100%" @change="handleModelChange">
|
|
|
- <el-option
|
|
|
- v-for="item in modelList"
|
|
|
- :label="item.modelName"
|
|
|
- :value="item.modelCode"
|
|
|
- :key="item.modelCode"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <!-- 这里可以展示属性名称和属性值 -->
|
|
|
- <div v-if="attrList.length > 0" class="attr-list-container">
|
|
|
- <h3>模型属性:</h3>
|
|
|
- <ul>
|
|
|
- <li v-for="attr in attrList" :key="attr.attrKey" class="attr-item">
|
|
|
- <span class="attr-name">{{ attr.attrName }} ({{ attr.attrUnit }}):</span>
|
|
|
- <!-- 使用 el-input 组件允许用户编辑属性值 -->
|
|
|
- <el-input
|
|
|
- v-model="attrValuesMap[attr.attrKey]"
|
|
|
- placeholder="点击编辑"
|
|
|
- size="small"
|
|
|
- @blur="updateAttrValue(attr.attrKey, attrValuesMap[attr.attrKey])"
|
|
|
- >
|
|
|
- </el-input>
|
|
|
- </li>
|
|
|
- </ul>
|
|
|
- </div>
|
|
|
- <h3 class="attr-list-container" v-if="attrList.length > 0">自定义属性
|
|
|
- <el-form-item label="" prop="attrList">
|
|
|
- <el-table class="attr-table" v-loading="loading" :data="form.customAttrs" max-height="280px"
|
|
|
- key="'customAttrs'"
|
|
|
- >
|
|
|
- <el-table-column label="标识" align="center" prop="attrKey">
|
|
|
- <template slot-scope="scope">
|
|
|
- <el-input size="mini" v-model="scope.row.attrKey" placeholder="请输入标识"/>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="属性名" align="center" prop="attrName">
|
|
|
- <template slot-scope="scope">
|
|
|
- <el-input size="mini" v-model="scope.row.attrName" placeholder="请输入属性名"/>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="属性值" align="center" prop="attrValue">
|
|
|
- <template slot-scope="scope">
|
|
|
- <el-input size="mini" v-model="scope.row.attrValue" placeholder="请输入属性值"/>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column align="center" label="操作">
|
|
|
- <template slot="header">
|
|
|
- <div class="operateBtns" @click="addCustomAttr">
|
|
|
- <span>添加</span><i class="el-icon-circle-plus-outline"></i>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- <template slot-scope="scope">
|
|
|
- <i class="el-icon-delete" @click="deleteCustomAttr(scope.$index)"></i>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
- </el-form-item>
|
|
|
- </h3>
|
|
|
- <el-form-item label="子系统" prop="subsystemCode">
|
|
|
- <el-select v-model="form.subsystemCode">
|
|
|
- <el-option v-for="item in subsystemOptions" :label="item.systemName" :value="item.systemCode"
|
|
|
- :key="item.systemCode"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
- <div slot="footer" class="dialog-footer">
|
|
|
- <el-button type="primary" @click="submitForm">确 定</el-button>
|
|
|
- <el-button @click="cancel">取 消</el-button>
|
|
|
- </div>
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
- <!--设备器件-->
|
|
|
- <el-drawer :title=ComponentRow.deviceName size="80%" :visible.sync="showDevProcessDrawer" direction="rtl">
|
|
|
- <div class="drawer-content" style="padding-left:50px">
|
|
|
- <el-row :gutter="10" class="mb8">
|
|
|
- <el-col :span="1.5">
|
|
|
- <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleComponentAdd"
|
|
|
- v-hasPermi="['ems:component:add']"
|
|
|
- >新增
|
|
|
- </el-button>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- <el-table v-loading="loading" :data="ComponentList">
|
|
|
- <el-table-column type="selection" width="55" align="center"/>
|
|
|
- <el-table-column label="部件编码" align="center" prop="compoCode"/>
|
|
|
- <el-table-column label="部件标签" align="center" prop="compoTag">
|
|
|
- <template slot-scope="scope">
|
|
|
- {{ objComTypeMapping[scope.row.compoTag] }}
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="工艺标识代码" align="center" prop="psCode"/>
|
|
|
- <el-table-column label="外系统部件编码" align="center" prop="extCompoCode"/>
|
|
|
- <el-table-column label="部件模型" align="center" prop="compoModel"/>
|
|
|
- <el-table-column label="部件品牌" align="center" prop="compoBrand"/>
|
|
|
- <el-table-column label="部件型号" align="center" prop="compoSpec"/>
|
|
|
- <el-table-column label="祖籍列表" align="center" prop="ancestors"/>
|
|
|
- <el-table-column label="上级部件" align="center" prop="parentEqpt"/>
|
|
|
-
|
|
|
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
|
|
- <template slot-scope="scope">
|
|
|
- <el-button size="mini" type="text" icon="el-icon-edit" @click="handleComponentUpdate(scope.row)"
|
|
|
- v-hasPermi="['ems:component:edit']"
|
|
|
- >
|
|
|
- 修改
|
|
|
- </el-button>
|
|
|
- <el-button size="mini" type="text" icon="el-icon-delete" class="deleteBtn"
|
|
|
- @click="handleComponentDelete(scope.row)" v-hasPermi="['ems:component:remove']"
|
|
|
- >
|
|
|
- 删除
|
|
|
- </el-button>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
- <pagination v-show="total>0" :total="total" :page.sync="queryComponentParams.pageNum"
|
|
|
- :limit.sync="queryComponentParams.pageSize"
|
|
|
- @pagination="getComponentList"
|
|
|
- />
|
|
|
-
|
|
|
- <!-- 添加或修改设备器件对话框 -->
|
|
|
- <el-dialog :title="title" :visible.sync="componentOpen" width="500px" append-to-body>
|
|
|
- <el-form ref="componentForm" :model="componentForm" :rules="componentRules" label-width="150px">
|
|
|
- <!-- <el-form-item label="设备code" prop="deviceCode">-->
|
|
|
- <!-- <el-input v-model="componentForm.deviceCode" placeholder="请输入设备code" />-->
|
|
|
- <!-- </el-form-item>-->
|
|
|
- <el-form-item label="部件编码" prop="compoCode">
|
|
|
- <el-input v-model="componentForm.compoCode" placeholder="请输入部件编码"/>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="部件标签" prop="compoTag">
|
|
|
- <el-select v-model="componentForm.compoTag" placeholder="请输入部件标签">
|
|
|
- <el-option v-for="item in objComTypeOptions"
|
|
|
- :label="item.name"
|
|
|
- :value="item.code"
|
|
|
- :key="item.code"
|
|
|
- />
|
|
|
-
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="工艺标签代码" prop="psCode">
|
|
|
- <el-select v-model="componentForm.psCode" placeholder="请输入工艺标签代码">
|
|
|
- <el-option v-for="item in devOptions" :label="item.psCode" :value="item.psCode"
|
|
|
- :key="item.psCode"/>
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="外系统部件编码" prop="extCompoCode">
|
|
|
- <el-input v-model="componentForm.extCompoCode" placeholder="请输入外系统部件编码"/>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="部件模型" prop="compoModel">
|
|
|
- <el-select v-model="componentForm.compoModel" placeholder="请输入部件模型">
|
|
|
- <el-option v-for="item in this.modelList" :label="item.modelCode" :value="item.modelCode"
|
|
|
- :key="item.modelCode"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="部件品牌" prop="compoBrand">
|
|
|
- <el-input v-model="componentForm.compoBrand" placeholder="请输入部件品牌"/>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="部件型号" prop="compoSpec">
|
|
|
- <el-input v-model="componentForm.compoSpec" placeholder="请输入部件型号"/>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="祖籍列表" prop="ancestors">
|
|
|
- <el-input v-model="componentForm.ancestors" placeholder="请输入祖籍列表"/>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="上级列表" prop="parentCompo">
|
|
|
- <el-input v-model="componentForm.parentCompo" placeholder="请输入上级列表"/>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- </el-form>
|
|
|
- <div slot="footer" class="dialog-footer">
|
|
|
- <el-button type="primary" @click="submitComponentForm">确 定</el-button>
|
|
|
- <el-button @click="ComponentCancel">取 消</el-button>
|
|
|
- </div>
|
|
|
- </el-dialog>
|
|
|
- </div>
|
|
|
- </el-drawer>
|
|
|
-
|
|
|
- <!-- 详情弹框 -->
|
|
|
- <el-dialog :visible.sync="showDrawer" title="设备详情">
|
|
|
- <div v-if="curRow">
|
|
|
- <!-- 设备基本信息 -->
|
|
|
- <el-card class="box-card">
|
|
|
- <div slot="header" class="clearfix">
|
|
|
- <span class="section-title">设备基本信息</span>
|
|
|
- </div>
|
|
|
- <div>
|
|
|
- <p>设备代码:{{ curRow.deviceCode }}</p>
|
|
|
- <p>设备名称:{{ curRow.deviceName }}</p>
|
|
|
- <p>设备类型:{{ curRow.deviceCategoryName }}</p>
|
|
|
- <p>子系统:{{ curRow.subsystemName }}</p>
|
|
|
- <p>归属区域:{{ curRow.areaPath }}</p>
|
|
|
- <p>归属设施:{{ curRow.refFacsName }}</p>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
- <el-card class="box-card" style="margin-top: 10px">
|
|
|
- <div slot="header" class="clearfix">
|
|
|
- <span class="section-title">状态属性</span>
|
|
|
- </div>
|
|
|
- <div>
|
|
|
- <p v-for="attr in statusAttr" :key="attr.attr">{{ attr.attr }}:{{ attr.attrValue }} {{
|
|
|
- attr.attrUnit
|
|
|
- }}</p>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
- <!-- 属性信息 -->
|
|
|
- <el-card class="box-card" v-if="attrData.length > 0">
|
|
|
- <div slot="header" class="clearfix">
|
|
|
- <span class="section-title">属性定义</span>
|
|
|
- </div>
|
|
|
- <div v-for="(item, index) in attrData" :key="index">
|
|
|
- <p>属性名称:{{ item.attrName }}</p>
|
|
|
- <p>属性值:{{ item.attrValue }}</p>
|
|
|
- <p>属性单位:{{ item.attrUnit }}</p>
|
|
|
- <!-- 在每个条目之后添加横线,除了最后一个条目 -->
|
|
|
- <div v-if="index < attrData.length - 1" class="divider"></div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
- <!-- 能力信息 -->
|
|
|
- <el-card class="box-card" v-if="abilityData.length > 0">
|
|
|
- <div slot="header" class="clearfix">
|
|
|
- <span class="section-title">能力定义</span>
|
|
|
- </div>
|
|
|
- <div v-for="(item, index) in abilityData" :key="index">
|
|
|
- <p>能力名称:{{ item.abilityName }}</p>
|
|
|
- <p>能力键:{{ item.abilityKey }}</p>
|
|
|
- <p>能力参数:{{ item.abilityParam }}</p>
|
|
|
- <p>能力描述:{{ item.abilityDesc }}</p>
|
|
|
- <!-- 在每个条目之后添加横线,除了最后一个条目 -->
|
|
|
- <div v-if="index < abilityData.length - 1" class="divider"></div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
- <!-- 事件信息 -->
|
|
|
- <el-card class="box-card" v-if="eventData.length > 0">
|
|
|
- <div slot="header" class="clearfix">
|
|
|
- <span class="section-title">事件定义</span>
|
|
|
- </div>
|
|
|
- <div v-for="(item, index) in eventData" :key="index">
|
|
|
- <p>事件名称:{{ item.eventKey }}</p>
|
|
|
- <p>事件类型:{{ item.eventType === 1 ? '消息上报' : '异常告警' }}</p>
|
|
|
- <p>事件代码:{{ item.eventCode }}</p>
|
|
|
- <p>外部事件代码:{{ item.extEventCode }}</p>
|
|
|
- <!-- 在每个条目之后添加横线,除了最后一个条目 -->
|
|
|
- <div v-if="index < eventData.length - 1" class="divider"></div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
- </div>
|
|
|
- </el-dialog>
|
|
|
+ <div style="margin-top: 20px;">
|
|
|
+ <h4>响应载体</h4>
|
|
|
+ <pre style="white-space: pre-wrap; background-color: #f5f5f5; padding: 10px; border-radius: 4px; max-height: 300px; overflow: auto;">{{ callLogDetailData.resPayload }}</pre>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 事件日志详情弹窗 -->
|
|
|
+ <el-dialog :visible.sync="eventLogDetailDialog" title="事件日志详情" width="60%">
|
|
|
+ <div v-if="eventLogDetailData">
|
|
|
+ <el-descriptions :column="2" border>
|
|
|
+ <el-descriptions-item label="对象编号">{{ eventLogDetailData.objCode }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="对象名称">{{ eventLogDetailData.objName }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="事件名称">{{ eventLogDetailData.eventName }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="事件标识">{{ eventLogDetailData.eventKey }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="事件时间" :span="2">{{ eventLogDetailData.eventTime }}</el-descriptions-item>
|
|
|
+ </el-descriptions>
|
|
|
+
|
|
|
+ <div style="margin-top: 20px;">
|
|
|
+ <h4>事件描述</h4>
|
|
|
+ <div style="background-color: #f5f5f5; padding: 10px; border-radius: 4px;">
|
|
|
+ {{ eventLogDetailData.eventDetail || '无' }}
|
|
|
</div>
|
|
|
</div>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import {addDevice, delDevice, getDevice, listDevRecursionByArea, updateDevice} from '@/api/device/device'
|
|
|
-import {areaTreeSelect} from '@/api/basecfg/area'
|
|
|
-import {getFacsCategorygetByCode, listAllFacs} from '@/api/basecfg/emsfacs'
|
|
|
-import {listSubsystemAll} from '@/api/adapter/subsystem'
|
|
|
-import {getModelByCode, listAllModel} from '@/api/basecfg/objModel'
|
|
|
-import {getObjAttr} from '@/api/basecfg/objAttribute'
|
|
|
-import {addAttrValueBatch} from '@/api/basecfg/objAttributeValue'
|
|
|
-import {addComponent, delComponent, getComponent, listByDevice, updateComponent} from '@/api/basecfg/component'
|
|
|
-import Treeselect from '@riophae/vue-treeselect'
|
|
|
-import '@riophae/vue-treeselect/dist/vue-treeselect.css'
|
|
|
+import { getSubsystemByCode } from '@/api/adapter/subsystem'
|
|
|
+import { getModelByCode } from '@/api/basecfg/objModel'
|
|
|
+import { getObjAttr } from '@/api/basecfg/objAttribute'
|
|
|
+import { listcallAbility } from '@/api/basecfg/objAbility'
|
|
|
+import { getByCondition } from '@/api/device/device'
|
|
|
+import { listCallLog, listEventLog, getCallLog, getEventLog } from '@/api/basecfg/objLog'
|
|
|
|
|
|
export default {
|
|
|
- name: 'Device',
|
|
|
- components: {Treeselect},
|
|
|
+ name: 'SubsystemIntegration',
|
|
|
data() {
|
|
|
return {
|
|
|
- primary1: 'primary',
|
|
|
- primary2: '',
|
|
|
- ComponentRow: [],
|
|
|
- componentForm: {},
|
|
|
- subcategoryCode: '',
|
|
|
- attrList: [], // 属性模板数组
|
|
|
- attrValues: [],
|
|
|
- ComponentList: [],
|
|
|
- attrValuesMap: {},
|
|
|
- modelList: [],
|
|
|
- showDrawer: false,
|
|
|
- showDevProcessDrawer: false,
|
|
|
- componentOpen: false,
|
|
|
- istable: 2,
|
|
|
- // 遮罩层
|
|
|
- loading: true,
|
|
|
- // 选中数组
|
|
|
- ids: [],
|
|
|
- // 非单个禁用
|
|
|
- single: true,
|
|
|
- // 非多个禁用
|
|
|
- multiple: true,
|
|
|
- // 显示搜索条件
|
|
|
- showSearch: true,
|
|
|
- // 总条数
|
|
|
- total: 0,
|
|
|
- // 能源设备表格数据
|
|
|
+ // 系统代码
|
|
|
+ systemCode: 'SYS_NHJC',
|
|
|
+ // 系统信息
|
|
|
+ systemInfo: {},
|
|
|
+ // 系统状态
|
|
|
+ systemStatus: '1',
|
|
|
+ // 当前标签页
|
|
|
+ activeTab: 'attributes',
|
|
|
+ // 协议属性
|
|
|
+ protocolAttrs: [],
|
|
|
+ // 状态属性
|
|
|
+ stateAttrs: [],
|
|
|
+ // 系统能力
|
|
|
+ systemAbilities: [],
|
|
|
+ abilityLoading: false,
|
|
|
+ // 设备列表
|
|
|
deviceList: [],
|
|
|
- // 弹出层标题
|
|
|
- title: '',
|
|
|
- // 是否显示弹出层
|
|
|
- open: false,
|
|
|
- // 区域名称
|
|
|
- areaName: undefined,
|
|
|
- // 区域树选项
|
|
|
- treeAreaOptions: undefined,
|
|
|
- totalAreaOptions: undefined,
|
|
|
- // 设施选项
|
|
|
- facsOptions: undefined,
|
|
|
- // 设备分类
|
|
|
- subCategoryOptions: undefined,
|
|
|
- subsystemOptions: undefined,
|
|
|
- devOptions: undefined,
|
|
|
-
|
|
|
- defaultProps: {
|
|
|
- children: 'children',
|
|
|
- label: 'label'
|
|
|
+ deviceLoading: false,
|
|
|
+ deviceAttrs: {},
|
|
|
+ deviceChannels: {},
|
|
|
+ // 设备能力缓存
|
|
|
+ deviceAbilities: {},
|
|
|
+ // 设备统计
|
|
|
+ deviceStats: {
|
|
|
+ total: 0,
|
|
|
+ online: 0,
|
|
|
+ offline: 0,
|
|
|
+ points: 0
|
|
|
},
|
|
|
- // 查询参数
|
|
|
- queryParams: {
|
|
|
- psCode: null,
|
|
|
+ // 所有模型代码(系统 + 设备)
|
|
|
+ allModelCodes: [],
|
|
|
+ // 调用日志查询
|
|
|
+ callLogQuery: {
|
|
|
+ dateRange: [],
|
|
|
+ abilityKey: '',
|
|
|
+ callStatus: '',
|
|
|
pageNum: 1,
|
|
|
- pageSize: 10,
|
|
|
- deviceCode: null,
|
|
|
- deviceSubCategory: '',
|
|
|
- deviceCategory: 'E',
|
|
|
- locationType: null,
|
|
|
- locationRef: null,
|
|
|
- refFacs: null,
|
|
|
- customAttrs: null
|
|
|
+ pageSize: 10
|
|
|
},
|
|
|
- queryComponentParams: {
|
|
|
+ callLogList: [],
|
|
|
+ callLogTotal: 0,
|
|
|
+ logLoading: false,
|
|
|
+ // 事件日志查询
|
|
|
+ eventLogQuery: {
|
|
|
+ dateRange: [],
|
|
|
+ eventKey: '',
|
|
|
pageNum: 1,
|
|
|
pageSize: 10
|
|
|
},
|
|
|
- objComTypeMapping: {
|
|
|
- 1: '总开',
|
|
|
- 2: '照明',
|
|
|
- 3: '风机'
|
|
|
- },
|
|
|
- objComTypeOptions: [
|
|
|
- {code: 1, name: '总开'},
|
|
|
- {code: 2, name: '照明'},
|
|
|
- {code: 3, name: '风机'}
|
|
|
-
|
|
|
- ],
|
|
|
- curRow: {},
|
|
|
- attrData: [],
|
|
|
- abilityData: [],
|
|
|
- eventData: [],
|
|
|
- statusAttr: [{
|
|
|
- attr: '用能',
|
|
|
- attrUnit: 'kW',
|
|
|
- attrValue: '10'
|
|
|
- },
|
|
|
- {
|
|
|
- attr: '能耗',
|
|
|
- attrUnit: 'kW·h',
|
|
|
- attrValue: '20'
|
|
|
- },
|
|
|
- {
|
|
|
- attr: '趋势',
|
|
|
- attrUnit: '',
|
|
|
- attrValue: '上升'
|
|
|
- },
|
|
|
- {
|
|
|
- attr: '能耗排名',
|
|
|
- attrUnit: '',
|
|
|
- attrValue: '1'
|
|
|
- }
|
|
|
- ],
|
|
|
- // 表单参数
|
|
|
- form: {
|
|
|
- customAttrs: [] // 自定义属性数组
|
|
|
- },
|
|
|
- // 表单校验
|
|
|
- rules: {
|
|
|
- refFacs: [
|
|
|
- {required: true, message: '归属设施', trigger: 'blur'}
|
|
|
- ],
|
|
|
- refArea: [
|
|
|
- {required: true, message: '安装位置', trigger: 'blur'}
|
|
|
- ],
|
|
|
- deviceCode: [
|
|
|
- {required: true, message: '设备代码不能为空', trigger: 'blur'}
|
|
|
- ],
|
|
|
- deviceName: [
|
|
|
- {required: true, message: '设备名称不能为空', trigger: 'blur'}
|
|
|
- ]
|
|
|
- },
|
|
|
- componentRules: {
|
|
|
- deviceCode: [
|
|
|
- {required: true, message: '设备code不能为空', trigger: 'blur'}
|
|
|
- ],
|
|
|
- compoCode: [
|
|
|
- {required: true, message: '部件编码不能为空', trigger: 'blur'}
|
|
|
- ],
|
|
|
- psCode: [
|
|
|
- {required: true, message: '工艺标签代码不能为空', trigger: 'blur'}
|
|
|
- ]
|
|
|
+ eventLogList: [],
|
|
|
+ eventLogTotal: 0,
|
|
|
+ eventLogLoading: false,
|
|
|
+ // 调用日志详情
|
|
|
+ callLogDetailDialog: false,
|
|
|
+ callLogDetailData: null,
|
|
|
+ // 事件日志详情
|
|
|
+ eventLogDetailDialog: false,
|
|
|
+ eventLogDetailData: null,
|
|
|
+ // 执行结果对话框
|
|
|
+ executeDialog: {
|
|
|
+ visible: false,
|
|
|
+ title: '',
|
|
|
+ status: '',
|
|
|
+ type: 'success',
|
|
|
+ message: '',
|
|
|
+ data: null
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
- watch: {
|
|
|
- // 根据名称筛选区域树
|
|
|
- areaName(val) {
|
|
|
- this.$refs.tree.filter(val)
|
|
|
- }
|
|
|
- },
|
|
|
created() {
|
|
|
- this.queryParams.deviceCategory = 'NHJC'; // 确保初始加载时就设置为 'NHJC'
|
|
|
- this.getList()
|
|
|
- this.getAreaTree('0', 1)
|
|
|
- this.getFacsOptions()
|
|
|
- this.getSubsystem()
|
|
|
- this.getSubCategorygetByCode()
|
|
|
- this.getFacsModel()
|
|
|
- // this.getAllDevProcess(this.subcategoryCode)
|
|
|
+ this.loadSystemInfo()
|
|
|
+ this.initDateRange()
|
|
|
},
|
|
|
methods: {
|
|
|
- /**分页切换*/
|
|
|
- switchData(v) {
|
|
|
- if (v === 1) {
|
|
|
- this.primary1 = "primary";
|
|
|
- this.primary2 = "";
|
|
|
- } else {
|
|
|
- this.primary1 = "";
|
|
|
- this.primary2 = "primary";
|
|
|
- }
|
|
|
- this.istable = v;
|
|
|
+ // 初始化时间范围(默认今天)
|
|
|
+ initDateRange() {
|
|
|
+ const now = new Date()
|
|
|
+ const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0)
|
|
|
+ const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59)
|
|
|
+
|
|
|
+ this.callLogQuery.dateRange = [
|
|
|
+ this.formatDate(startOfDay),
|
|
|
+ this.formatDate(endOfDay)
|
|
|
+ ]
|
|
|
+ this.eventLogQuery.dateRange = [
|
|
|
+ this.formatDate(startOfDay),
|
|
|
+ this.formatDate(endOfDay)
|
|
|
+ ]
|
|
|
},
|
|
|
- /** 查询能源设备列表 */
|
|
|
- getList() {
|
|
|
- this.loading = true
|
|
|
- listDevRecursionByArea(this.queryParams).then(response => {
|
|
|
- console.log('参数', JSON.stringify(this.queryParams))
|
|
|
- this.deviceList = response.rows
|
|
|
- this.total = response.total
|
|
|
- this.loading = false
|
|
|
- })
|
|
|
- },
|
|
|
- /**新增、修改、删除*/
|
|
|
- handleComponentAdd() {
|
|
|
- this.componentReset()
|
|
|
- this.componentOpen = true
|
|
|
- this.title = '添加设备器件属性'
|
|
|
- this.componentForm.deviceCode = this.ComponentRow.deviceCode // 设置默认设备代码
|
|
|
|
|
|
+ // 格式化日期
|
|
|
+ formatDate(date) {
|
|
|
+ if (!date) return ''
|
|
|
+ const year = date.getFullYear()
|
|
|
+ const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
|
|
+ const day = date.getDate().toString().padStart(2, '0')
|
|
|
+ const hours = date.getHours().toString().padStart(2, '0')
|
|
|
+ const minutes = date.getMinutes().toString().padStart(2, '0')
|
|
|
+ const seconds = date.getSeconds().toString().padStart(2, '0')
|
|
|
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
|
},
|
|
|
- handleComponentUpdate(row) {
|
|
|
- this.componentReset()
|
|
|
- const id = row.id || this.ids
|
|
|
- getComponent(id).then(response => {
|
|
|
- this.componentForm = response.data
|
|
|
- this.componentOpen = true
|
|
|
- this.title = '修改设备器件属性'
|
|
|
- this.componentForm.deviceCode = this.ComponentRow.deviceCode // 设置默认设备代码
|
|
|
- })
|
|
|
- },
|
|
|
- handleComponentDelete(row) {
|
|
|
- const ids = row.id || this.ids
|
|
|
- this.$modal.confirm('是否确认删除能源对象属性编号为"' + ids + '"的数据项?').then(function () {
|
|
|
- return delComponent(ids)
|
|
|
- }).then(() => {
|
|
|
- console.log('删除row', row.deviceCode)
|
|
|
- this.getComponentList(row.deviceCode)
|
|
|
- this.$modal.msgSuccess('删除成功')
|
|
|
- }).catch(() => {
|
|
|
- })
|
|
|
- },
|
|
|
- submitComponentForm() {
|
|
|
- this.$refs['componentForm'].validate(valid => {
|
|
|
- if (valid) {
|
|
|
- if (this.componentForm.id != null) {
|
|
|
- updateComponent(this.componentForm).then(response => {
|
|
|
- this.$modal.msgSuccess('修改成功')
|
|
|
- this.componentOpen = false
|
|
|
- this.getComponentList(this.componentForm.deviceCode)
|
|
|
- })
|
|
|
- } else {
|
|
|
- addComponent(this.componentForm).then(response => {
|
|
|
- this.$modal.msgSuccess('新增成功')
|
|
|
- this.componentOpen = false
|
|
|
- this.getComponentList(this.componentForm.deviceCode)
|
|
|
- })
|
|
|
- }
|
|
|
+
|
|
|
+ // 加载系统信息
|
|
|
+ async loadSystemInfo() {
|
|
|
+ try {
|
|
|
+ // 1. 获取系统基础信息
|
|
|
+ const sysRes = await getSubsystemByCode(this.systemCode)
|
|
|
+ this.systemInfo = sysRes.data
|
|
|
+
|
|
|
+ // 2. 获取模型信息
|
|
|
+ if (this.systemInfo.modelCode) {
|
|
|
+ // 添加系统模型代码
|
|
|
+ this.allModelCodes.push(this.systemInfo.modelCode)
|
|
|
+
|
|
|
+ const modelRes = await getModelByCode(this.systemInfo.modelCode)
|
|
|
+ const modelData = modelRes.data
|
|
|
+
|
|
|
+ // 获取能力列表
|
|
|
+ this.systemAbilities = (modelData.abilityList || []).map(item => ({
|
|
|
+ ...item,
|
|
|
+ executing: false
|
|
|
+ }))
|
|
|
}
|
|
|
- })
|
|
|
- },
|
|
|
- ComponentCancel() {
|
|
|
- this.componentOpen = false
|
|
|
- this.componentReset()
|
|
|
- },
|
|
|
- /**查询部件列表*/
|
|
|
- getComponentList(deviceCode) {
|
|
|
- listByDevice(deviceCode).then(response => {
|
|
|
- this.ComponentList = response.data
|
|
|
- })
|
|
|
- },
|
|
|
- /** 查询区域树结构 */
|
|
|
- getAreaTree(areaCode, layer) {
|
|
|
- areaTreeSelect(areaCode, layer).then(response => {
|
|
|
- this.treeAreaOptions = [{
|
|
|
- id: '-1',
|
|
|
- label: '全部',
|
|
|
- children: response.data
|
|
|
- }]
|
|
|
- })
|
|
|
- },
|
|
|
- // 筛选节点
|
|
|
- filterNode(value, data) {
|
|
|
- if (!value) return true
|
|
|
- return data.label.indexOf(value) !== -1
|
|
|
- },
|
|
|
- // 节点单击事件
|
|
|
- handleNodeClick(data) {
|
|
|
- if (data.id === '-1') {
|
|
|
- this.queryParams.locationType = null;
|
|
|
- this.queryParams.locationRef = null;
|
|
|
- } else {
|
|
|
- this.queryParams.locationType = data.tier;
|
|
|
- this.queryParams.locationRef = data.id;
|
|
|
- }
|
|
|
- this.handleQuery();
|
|
|
- },
|
|
|
- // 取消按钮
|
|
|
- cancel() {
|
|
|
- this.open = false
|
|
|
- this.reset()
|
|
|
- },
|
|
|
- // 表单重置
|
|
|
- reset() {
|
|
|
- this.form = {
|
|
|
- id: null,
|
|
|
- deviceCode: null,
|
|
|
- deviceName: null,
|
|
|
- deviceType: null,
|
|
|
- deviceStatus: null,
|
|
|
- deviceModel: null,
|
|
|
- refArea: null,
|
|
|
- refFacs: null,
|
|
|
- subsystemCode: null,
|
|
|
- psCode: null,
|
|
|
- createTime: null,
|
|
|
- updateTime: null
|
|
|
|
|
|
- }
|
|
|
- this.resetForm('form')
|
|
|
- },
|
|
|
- componentReset() {
|
|
|
- this.componentForm = {
|
|
|
- id: null,
|
|
|
- deviceCode: this.ComponentRow.deviceCode || '', // 使用ComponentRow的deviceCode,或者空字符串
|
|
|
- compoCode: null,
|
|
|
- compoTag: null,
|
|
|
- psCode: null,
|
|
|
- extCompoCode: null,
|
|
|
- compoModel: null,
|
|
|
- compoBrand: null,
|
|
|
- compoSpec: null,
|
|
|
- ancestors: null,
|
|
|
- parentCompo: null
|
|
|
+ // 3. 获取系统属性值
|
|
|
+ const attrRes = await getObjAttr(3, this.systemCode)
|
|
|
+ const attrData = attrRes.data
|
|
|
|
|
|
- }
|
|
|
- this.resetForm('componentForm')
|
|
|
- },
|
|
|
- /** 搜索按钮操作 */
|
|
|
- handleQuery() {
|
|
|
- this.queryParams.pageNum = 1
|
|
|
- console.log('搜索按钮this.queryParams', JSON.stringify(this.queryParams))
|
|
|
- this.getList()
|
|
|
- },
|
|
|
- /** 重置按钮操作 */
|
|
|
- resetQuery() {
|
|
|
- this.queryParams.locationType = null
|
|
|
- this.queryParams.locationRef = null
|
|
|
- this.resetForm('queryForm')
|
|
|
- this.handleQuery()
|
|
|
- },
|
|
|
- // 多选框选中数据
|
|
|
- handleSelectionChange(selection) {
|
|
|
- this.ids = selection.map(item => item.id)
|
|
|
- this.single = selection.length !== 1
|
|
|
- this.multiple = !selection.length
|
|
|
- },
|
|
|
- /** 新增按钮操作 */
|
|
|
- handleAdd() {
|
|
|
- this.reset()
|
|
|
- this.open = true
|
|
|
- this.title = '添加能源设备'
|
|
|
- },
|
|
|
- /**设备器件按钮*/
|
|
|
- handleDevProcess(row) {
|
|
|
- this.showDevProcessDrawer = true
|
|
|
- this.ComponentRow = row
|
|
|
- console.log('row', row)
|
|
|
- listByDevice(this.ComponentRow.deviceCode).then(response => {
|
|
|
- this.ComponentList = response.data
|
|
|
- })
|
|
|
+ this.protocolAttrs = attrData.Protocol || []
|
|
|
+ this.stateAttrs = attrData.State || []
|
|
|
|
|
|
- },
|
|
|
- shouldShowDevProcessButton(row) {
|
|
|
- const categoryIsW = this.queryParams.deviceCategory === 'W'
|
|
|
- const validPsCodes = ['AA', 'AH', 'AJ', 'AM', 'AP', 'AL', 'APE', 'ALE', 'AF', 'ACC']
|
|
|
- const psCodeIsValid = validPsCodes.includes(row.psCode)
|
|
|
- // 只有当设备分类为输能设备且设备工艺代码有效时,才返回true
|
|
|
- return categoryIsW && psCodeIsValid
|
|
|
- },
|
|
|
- backStyle(areaPath) {
|
|
|
- const firstLevel = areaPath.split('/')[0];
|
|
|
- switch (firstLevel) {
|
|
|
- case '北区':
|
|
|
- return 'north';
|
|
|
- case '南区':
|
|
|
- return 'south';
|
|
|
- case '主路':
|
|
|
- return 'main';
|
|
|
- default:
|
|
|
- return '';
|
|
|
+ // 设置系统状态
|
|
|
+ const statusAttr = this.stateAttrs.find(attr => attr.attrKey === 'interfaceStatus')
|
|
|
+ if (statusAttr) {
|
|
|
+ this.systemStatus = statusAttr.attrValue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 加载关联设备
|
|
|
+ await this.loadDevices()
|
|
|
+ } catch (error) {
|
|
|
+ this.$message.error('加载系统信息失败:' + error.message)
|
|
|
}
|
|
|
},
|
|
|
- /**设备详情按钮*/
|
|
|
- handleDetail(row) {
|
|
|
- this.showDrawer = true
|
|
|
- this.curRow = row
|
|
|
- console.log('data', this.curRow)
|
|
|
- this.subKey = this.$options.data().subKey
|
|
|
- getModelByCode(this.curRow.facsModel).then(response => {
|
|
|
- const code = response.data
|
|
|
- console.log('code', code)
|
|
|
- this.eventData = response.data.eventList
|
|
|
- this.abilityData = response.data.abilityList
|
|
|
-
|
|
|
- })
|
|
|
- getObjAttr(2, this.curRow.deviceCode).then(response => {
|
|
|
- console.log('response值', response.data)
|
|
|
- const attrs = response.data.attrs
|
|
|
- const attrValues = response.data.attrValues
|
|
|
-
|
|
|
- // 合并 attrs 和 attrValues 数组
|
|
|
- const mergedData = attrValues.map(attrValue => {
|
|
|
- const attr = attrs.find(a => a.attrKey === attrValue.attrKey)
|
|
|
- return {
|
|
|
- ...attrValue,
|
|
|
- attrName: attr ? attr.attrName : attrValue.attrName,
|
|
|
- attrUnit: attr ? attr.attrUnit : ''
|
|
|
+
|
|
|
+ // 加载设备列表
|
|
|
+ async loadDevices() {
|
|
|
+ this.deviceLoading = true
|
|
|
+ try {
|
|
|
+ const res = await getByCondition({
|
|
|
+ subsystemCode: this.systemCode
|
|
|
+ })
|
|
|
+
|
|
|
+ // 兼容不同的数据结构
|
|
|
+ const deviceData = res.data || res.rows || []
|
|
|
+
|
|
|
+ this.deviceList = deviceData.map(device => ({
|
|
|
+ ...device,
|
|
|
+ detailTab: 'attrs'
|
|
|
+ }))
|
|
|
+
|
|
|
+ // 收集所有设备的模型代码
|
|
|
+ const deviceModelCodes = new Set()
|
|
|
+ this.deviceList.forEach(device => {
|
|
|
+ if (device.deviceModel) {
|
|
|
+ deviceModelCodes.add(device.deviceModel)
|
|
|
}
|
|
|
})
|
|
|
- this.attrData = mergedData
|
|
|
- })
|
|
|
- },
|
|
|
- /** 修改按钮操作 */
|
|
|
- handleUpdate(row) {
|
|
|
- this.reset()
|
|
|
- const id = row.id || this.ids
|
|
|
- getDevice(id).then(response => {
|
|
|
- this.form = response.data
|
|
|
- this.open = true
|
|
|
- this.title = '修改能源设备'
|
|
|
- })
|
|
|
- const layer = 1
|
|
|
- const areaCode = '0'
|
|
|
- areaTreeSelect(areaCode, layer).then(response => {
|
|
|
- this.totalAreaOptions = response.data
|
|
|
- })
|
|
|
- },
|
|
|
- /** 提交按钮 */
|
|
|
- submitForm() {
|
|
|
- // 重置 attrList 和 form.customAttrs
|
|
|
- if (!this.attrList) {
|
|
|
- this.attrList = []
|
|
|
- }
|
|
|
- if (!this.form.customAttrs) {
|
|
|
- this.form.customAttrs = []
|
|
|
- }
|
|
|
- // 准备要发送的数据
|
|
|
- let dataToSubmit = []
|
|
|
- // 添加模型属性数据
|
|
|
- this.attrList.forEach(attr => {
|
|
|
- const attrName = attr.attrName
|
|
|
- const attrKey = attr.attrKey
|
|
|
- const attrValue = this.attrValuesMap[attrKey]
|
|
|
- const existingIndex = dataToSubmit.findIndex(item => item.attrKey === attrKey)
|
|
|
- if (existingIndex === -1) {
|
|
|
- // 如果attrKey不存在于dataToSubmit中,则添加
|
|
|
- dataToSubmit.push({
|
|
|
- modelCode: this.form.deviceModel, // 模型代码
|
|
|
- objCode: this.form.deviceCode, // 设备代码
|
|
|
- objType: 2, // 对象类型
|
|
|
- attrKey: attrKey,
|
|
|
- attrValue: attrValue,
|
|
|
- attrName: attrName
|
|
|
|
|
|
- })
|
|
|
+ // 将设备模型代码添加到总列表
|
|
|
+ deviceModelCodes.forEach(modelCode => {
|
|
|
+ if (!this.allModelCodes.includes(modelCode)) {
|
|
|
+ this.allModelCodes.push(modelCode)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 统计设备信息
|
|
|
+ this.deviceStats.total = this.deviceList.length
|
|
|
+ this.deviceStats.online = this.deviceList.filter(d => d.deviceStatus === 1).length
|
|
|
+ this.deviceStats.offline = this.deviceList.filter(d => d.deviceStatus !== 1).length
|
|
|
+
|
|
|
+ // 加载每个设备的属性
|
|
|
+ for (const device of this.deviceList) {
|
|
|
+ await this.loadDeviceAttrs(device.deviceCode)
|
|
|
}
|
|
|
- })
|
|
|
-
|
|
|
- // 添加自定义属性数据
|
|
|
- this.form.customAttrs.forEach(customAttr => {
|
|
|
- const attrName = customAttr.attrName
|
|
|
- const attrKey = customAttr.attrKey
|
|
|
- const attrValue = customAttr.attrValue
|
|
|
- const existingIndex = dataToSubmit.findIndex(item => item.attrKey === attrKey)
|
|
|
- if (existingIndex === -1) {
|
|
|
- // 如果attrKey不存在于dataToSubmit中,则添加
|
|
|
- dataToSubmit.push({
|
|
|
- modelCode: '', // 模型代码
|
|
|
- objCode: this.form.deviceCode, // 设备代码
|
|
|
- objType: 2, // 对象类型
|
|
|
- attrKey: attrKey,
|
|
|
- attrValue: attrValue,
|
|
|
- attrName: attrName
|
|
|
+ } catch (error) {
|
|
|
+ this.$message.error('加载设备列表失败')
|
|
|
+ } finally {
|
|
|
+ this.deviceLoading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 加载设备属性
|
|
|
+ async loadDeviceAttrs(deviceCode) {
|
|
|
+ try {
|
|
|
+ const res = await getObjAttr(2, deviceCode)
|
|
|
+ const attrData = res.data
|
|
|
+
|
|
|
+ // 存储基础属性
|
|
|
+ const baseAttrs = {}
|
|
|
+ if (attrData.Base) {
|
|
|
+ attrData.Base.forEach(attr => {
|
|
|
+ baseAttrs[attr.attrKey] = attr.attrValue
|
|
|
})
|
|
|
}
|
|
|
- })
|
|
|
-
|
|
|
- this.$refs['form'].validate(valid => {
|
|
|
- if (valid) {
|
|
|
- if (this.form.id != null) {
|
|
|
- updateDevice(this.form).then(response => {
|
|
|
- this.$modal.msgSuccess('修改成功')
|
|
|
- this.open = false
|
|
|
- this.getList()
|
|
|
- }).catch(error => {
|
|
|
- console.error('修改失败:', error)
|
|
|
- this.$message.error('修改失败')
|
|
|
- })
|
|
|
-
|
|
|
- if (dataToSubmit.length > 0) {
|
|
|
- addAttrValueBatch(dataToSubmit)
|
|
|
- .then(response => {
|
|
|
- if (response.code === 200) {
|
|
|
- this.$message.success('属性添加成功')
|
|
|
- } else {
|
|
|
- this.$message.error('属性添加失败')
|
|
|
- }
|
|
|
- }).catch(error => {
|
|
|
- console.error('属性添加失败:', error)
|
|
|
- this.$message.error('属性添加失败')
|
|
|
- })
|
|
|
+ this.deviceAttrs[deviceCode] = baseAttrs
|
|
|
+
|
|
|
+ // 处理测点通道信息
|
|
|
+ const channels = []
|
|
|
+ if (attrData.Measure) {
|
|
|
+ attrData.Measure.forEach(attr => {
|
|
|
+ if (attr.attrKey.startsWith('interface')) {
|
|
|
+ try {
|
|
|
+ const points = JSON.parse(attr.attrValue || '[]')
|
|
|
+ channels.push({
|
|
|
+ name: attr.attrName,
|
|
|
+ key: attr.attrKey,
|
|
|
+ points: points
|
|
|
+ })
|
|
|
+ // 统计测点数
|
|
|
+ this.deviceStats.points += points.length
|
|
|
+ } catch (e) {
|
|
|
+ // 忽略解析错误
|
|
|
+ }
|
|
|
}
|
|
|
- } else {
|
|
|
- addDevice(this.form).then(response => {
|
|
|
- this.$modal.msgSuccess('新增成功')
|
|
|
- this.open = false
|
|
|
- this.getList()
|
|
|
- }).catch(error => {
|
|
|
- console.error('新增失败:', error)
|
|
|
- this.$message.error('新增失败')
|
|
|
- })
|
|
|
-
|
|
|
- if (dataToSubmit.length > 0) {
|
|
|
- addAttrValueBatch(dataToSubmit)
|
|
|
- .then(response => {
|
|
|
- if (response.code === 200) {
|
|
|
- this.$message.success('属性添加成功')
|
|
|
- } else {
|
|
|
- this.$message.error('属性添加失败')
|
|
|
- }
|
|
|
- }).catch(error => {
|
|
|
- console.error('属性添加失败:', error)
|
|
|
- this.$message.error('属性添加失败')
|
|
|
- })
|
|
|
- } else {
|
|
|
- // this.$message.info('没有属性需要添加');
|
|
|
- }
|
|
|
- }
|
|
|
+ })
|
|
|
}
|
|
|
- })
|
|
|
- },
|
|
|
- /** 删除按钮操作 */
|
|
|
- handleDelete(row) {
|
|
|
- const ids = row.id || this.ids
|
|
|
- this.$modal.confirm('是否确认删除能源设备编号为"' + ids + '"的数据项?').then(function () {
|
|
|
- return delDevice(ids)
|
|
|
- }).then(() => {
|
|
|
- this.getList()
|
|
|
- this.$modal.msgSuccess('删除成功')
|
|
|
- }).catch(() => {
|
|
|
- })
|
|
|
- },
|
|
|
- /** 导出按钮操作 */
|
|
|
- handleExport() {
|
|
|
- this.download('ems/basecfg/device/export', {
|
|
|
- ...this.queryParams
|
|
|
- }, `device_${new Date().getTime()}.xlsx`)
|
|
|
- },
|
|
|
- getFacsOptions() {
|
|
|
- const getFacsParams = {
|
|
|
- facsCategory: this.queryParams.deviceCategory,
|
|
|
- subCategory: this.queryParams.deviceSubCategory
|
|
|
+ this.deviceChannels[deviceCode] = channels
|
|
|
+ } catch (error) {
|
|
|
+ // 忽略加载错误
|
|
|
}
|
|
|
- listAllFacs(getFacsParams).then(response => {
|
|
|
- this.facsOptions = response.data
|
|
|
- })
|
|
|
- },
|
|
|
- getSubCategorygetByCode() {
|
|
|
- getFacsCategorygetByCode(this.queryParams.deviceCategory).then(response => {
|
|
|
- this.subCategoryOptions = response.data.subtypeList || []
|
|
|
- })
|
|
|
- },
|
|
|
- getSubsystem() {
|
|
|
- listSubsystemAll().then(response => {
|
|
|
- this.subsystemOptions = response.data
|
|
|
- })
|
|
|
},
|
|
|
- /**自定义属性表格*/
|
|
|
- addCustomAttr() {
|
|
|
- // 添加一个新的自定义属性
|
|
|
- if (!Array.isArray(this.form.customAttrs)) {
|
|
|
- this.form.customAttrs = []
|
|
|
- }
|
|
|
- this.form.customAttrs.push({
|
|
|
- attrKey: '',
|
|
|
- attrName: '',
|
|
|
- attrValue: ''
|
|
|
- })
|
|
|
- // 强制更新视图
|
|
|
- this.$forceUpdate()
|
|
|
|
|
|
+ // 获取设备属性
|
|
|
+ getDeviceAttr(deviceCode, attrKey) {
|
|
|
+ return this.deviceAttrs[deviceCode]?.[attrKey] || '-'
|
|
|
},
|
|
|
- deleteCustomAttr(index) {
|
|
|
- // 删除指定索引的自定义属性
|
|
|
- if (this.form.customAttrs.length > 0) {
|
|
|
- this.form.customAttrs.splice(index, 1)
|
|
|
- }
|
|
|
|
|
|
+ // 获取设备通道
|
|
|
+ getDeviceChannels(deviceCode) {
|
|
|
+ return this.deviceChannels[deviceCode] || []
|
|
|
},
|
|
|
- /**设备模型*/
|
|
|
- updateAttrValue(attrKey, newValue) {
|
|
|
- this.attrValuesMap[attrKey] = newValue
|
|
|
+
|
|
|
+ // 加载设备能力(当下拉菜单显示时)
|
|
|
+ async handleAbilityLoad(visible, device) {
|
|
|
+ if (visible && !this.deviceAbilities[device.deviceCode]) {
|
|
|
+ try {
|
|
|
+ // 确保设备有模型代码
|
|
|
+ if (!device.deviceModel) {
|
|
|
+ this.$set(this.deviceAbilities, device.deviceCode, [])
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const res = await getModelByCode(device.deviceModel)
|
|
|
+ // 获取能力列表,hiddenFlag = 1 表示在操作菜单中显示的能力
|
|
|
+ const abilities = res.data?.abilityList?.filter(item => item.hiddenFlag === 1) || []
|
|
|
+ this.$set(this.deviceAbilities, device.deviceCode, abilities)
|
|
|
+ } catch (error) {
|
|
|
+ this.$set(this.deviceAbilities, device.deviceCode, [])
|
|
|
+ }
|
|
|
+ }
|
|
|
},
|
|
|
|
|
|
- getFacsModel() {
|
|
|
- listAllModel(2).then(response => {
|
|
|
- this.modelList = response.data
|
|
|
- console.log('this.modelList', this.modelList)
|
|
|
- this.modelList.forEach(model => {
|
|
|
- console.log(model.modelCode)
|
|
|
+ // 处理设备操作命令
|
|
|
+ async handleDeviceCommand(command) {
|
|
|
+ const { device, ability } = command
|
|
|
+ try {
|
|
|
+ await listcallAbility({
|
|
|
+ objCode: device.deviceCode,
|
|
|
+ objType: 2,
|
|
|
+ modelCode: device.deviceModel,
|
|
|
+ abilityKey: ability.abilityKey,
|
|
|
+ abilityParam: ability.abilityParam
|
|
|
})
|
|
|
- })
|
|
|
+
|
|
|
+ this.$message.success(`${ability.abilityName}执行成功`)
|
|
|
+
|
|
|
+ // 如果是抄表相关能力,重新加载设备属性
|
|
|
+ if (ability.abilityKey.toLowerCase().includes('meter') ||
|
|
|
+ ability.abilityKey.toLowerCase().includes('reading')) {
|
|
|
+ await this.loadDeviceAttrs(device.deviceCode)
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ this.$message.error(`${ability.abilityName}执行失败:${error.message}`)
|
|
|
+ }
|
|
|
},
|
|
|
- handleModelChange(modelCode) {
|
|
|
- if (modelCode) {
|
|
|
- this.getModelByCode(modelCode)
|
|
|
- console.log('设备代码', this.form.deviceCode)
|
|
|
- this.getObjAttr(2, this.form.deviceCode)
|
|
|
+
|
|
|
+ // 执行系统能力
|
|
|
+ async executeAbility(ability) {
|
|
|
+ ability.executing = true
|
|
|
+ try {
|
|
|
+ const res = await listcallAbility({
|
|
|
+ objCode: this.systemCode,
|
|
|
+ objType: 3,
|
|
|
+ modelCode: this.systemInfo.modelCode,
|
|
|
+ abilityKey: ability.abilityKey,
|
|
|
+ abilityParam: ability.abilityParam
|
|
|
+ })
|
|
|
+
|
|
|
+ this.executeDialog = {
|
|
|
+ visible: true,
|
|
|
+ title: '执行结果 - ' + ability.abilityName,
|
|
|
+ status: '执行成功',
|
|
|
+ type: 'success',
|
|
|
+ message: '系统能力执行完成',
|
|
|
+ data: res.data
|
|
|
+ }
|
|
|
+
|
|
|
+ // 刷新设备数据
|
|
|
+ if (ability.abilityKey === 'MeterReadingGw') {
|
|
|
+ this.loadDevices()
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ this.executeDialog = {
|
|
|
+ visible: true,
|
|
|
+ title: '执行结果 - ' + ability.abilityName,
|
|
|
+ status: '执行失败',
|
|
|
+ type: 'error',
|
|
|
+ message: error.message,
|
|
|
+ data: null
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ ability.executing = false
|
|
|
}
|
|
|
},
|
|
|
- getModelByCode(modelCode) {
|
|
|
- getModelByCode(modelCode).then(response => {
|
|
|
- // this.attrList = response.data.attrList;
|
|
|
- const filteredAttrList = response.data.attrList.filter(attr => attr.attrType === 0)
|
|
|
- this.attrList = filteredAttrList
|
|
|
|
|
|
- })
|
|
|
+ // 处理设备行点击 - 展开/收起行详情
|
|
|
+ handleDeviceClick(row) {
|
|
|
+ this.$refs.deviceTable?.toggleRowExpansion(row)
|
|
|
},
|
|
|
- getObjAttr(objType, deviceCode) {
|
|
|
- getObjAttr(objType, deviceCode).then(response => {
|
|
|
- // const attrs = response.data.attrs;
|
|
|
- const attrs = response.data.attrs.filter(attr => attr.attrType === 0)
|
|
|
- console.log('attrs', attrs)
|
|
|
- const attrValues = response.data.attrValues || [] // 确保是一个数组
|
|
|
- console.log('attrValues', attrValues)
|
|
|
-
|
|
|
- // 创建一个映射对象,用于存储 attrKey 与对应的 attrValue
|
|
|
- const attrValuesMap = {}
|
|
|
-
|
|
|
- // 遍历 attrs 数组
|
|
|
- attrs.forEach(attr => {
|
|
|
- // 查找 attrValues 数组中是否有匹配的 attrKey
|
|
|
- const attrValueObj = attrValues.find(value => value.attrKey === attr.attrKey)
|
|
|
- // 如果找到匹配的 attrValue,更新 attrValuesMap
|
|
|
- if (attrValueObj) {
|
|
|
- attrValuesMap[attr.attrKey] = attrValueObj.attrValue
|
|
|
- } else {
|
|
|
- // 如果没有找到匹配的 attrValue,则设置为 '暂无数据'
|
|
|
- attrValuesMap[attr.attrKey] = ''
|
|
|
- }
|
|
|
- })
|
|
|
|
|
|
- // 更新 attrValuesMap 到组件的数据中
|
|
|
- this.attrValuesMap = attrValuesMap
|
|
|
- // 打印更新后的 attrValuesMap,用于调试
|
|
|
- console.log('Updated attrValuesMap', this.attrValuesMap)
|
|
|
+ // 标签页切换
|
|
|
+ handleTabClick(tab) {
|
|
|
+ if (tab.name === 'callLogs' && this.callLogList.length === 0) {
|
|
|
+ this.queryCallLogs()
|
|
|
+ } else if (tab.name === 'eventLogs' && this.eventLogList.length === 0) {
|
|
|
+ this.queryEventLogs()
|
|
|
+ }
|
|
|
+ },
|
|
|
|
|
|
- })
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-</script>
|
|
|
-<style lang="scss" scoped>
|
|
|
+ // 查询调用日志
|
|
|
+ async queryCallLogs() {
|
|
|
+ this.logLoading = true
|
|
|
+ try {
|
|
|
+ const params = {
|
|
|
+ modelCodes: this.allModelCodes,
|
|
|
+ pageNum: this.callLogQuery.pageNum,
|
|
|
+ pageSize: this.callLogQuery.pageSize
|
|
|
+ }
|
|
|
|
|
|
-.divider {
|
|
|
- border-bottom: 2px solid #ebeef5;
|
|
|
- margin: 10px 0;
|
|
|
-}
|
|
|
+ // 添加时间范围
|
|
|
+ if (this.callLogQuery.dateRange && this.callLogQuery.dateRange.length === 2) {
|
|
|
+ params.startRecTime = this.callLogQuery.dateRange[0]
|
|
|
+ params.endRecTime = this.callLogQuery.dateRange[1]
|
|
|
+ }
|
|
|
|
|
|
-.section-title {
|
|
|
- font-size: 18px;
|
|
|
- font-weight: bold;
|
|
|
- margin-top: 20px;
|
|
|
- margin-bottom: 10px;
|
|
|
-}
|
|
|
+ // 添加能力标识
|
|
|
+ if (this.callLogQuery.abilityKey) {
|
|
|
+ params.abilityKey = this.callLogQuery.abilityKey
|
|
|
+ }
|
|
|
|
|
|
-.drawer-content {
|
|
|
- padding: 0 20px;
|
|
|
-}
|
|
|
+ // 添加调用状态
|
|
|
+ if (this.callLogQuery.callStatus !== '') {
|
|
|
+ params.callStatus = this.callLogQuery.callStatus
|
|
|
+ }
|
|
|
|
|
|
+ const res = await listCallLog(params)
|
|
|
+ this.callLogList = res.rows || []
|
|
|
+ this.callLogTotal = res.total || 0
|
|
|
+ } catch (error) {
|
|
|
+ this.$message.error('查询调用日志失败')
|
|
|
+ } finally {
|
|
|
+ this.logLoading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
|
|
|
-.section-title {
|
|
|
- font-size: 18px;
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
+ // 重置调用日志查询
|
|
|
+ resetCallLogQuery() {
|
|
|
+ this.initDateRange()
|
|
|
+ this.callLogQuery.abilityKey = ''
|
|
|
+ this.callLogQuery.callStatus = ''
|
|
|
+ this.callLogQuery.pageNum = 1
|
|
|
+ this.queryCallLogs()
|
|
|
+ },
|
|
|
|
|
|
-.attr-list-container {
|
|
|
- border: 1px solid #ccc;
|
|
|
- padding: 10px;
|
|
|
- margin: 10px 0;
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
+ // 查询事件日志
|
|
|
+ async queryEventLogs() {
|
|
|
+ this.eventLogLoading = true
|
|
|
+ try {
|
|
|
+ const params = {
|
|
|
+ modelCodes: this.allModelCodes,
|
|
|
+ pageNum: this.eventLogQuery.pageNum,
|
|
|
+ pageSize: this.eventLogQuery.pageSize
|
|
|
+ }
|
|
|
|
|
|
-.attr-list-container h3 {
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
+ // 添加时间范围
|
|
|
+ if (this.eventLogQuery.dateRange && this.eventLogQuery.dateRange.length === 2) {
|
|
|
+ params.startRecTime = this.eventLogQuery.dateRange[0]
|
|
|
+ params.endRecTime = this.eventLogQuery.dateRange[1]
|
|
|
+ }
|
|
|
|
|
|
-.attr-item {
|
|
|
- list-style-type: none;
|
|
|
- margin-bottom: 5px;
|
|
|
-}
|
|
|
+ // 添加事件标识
|
|
|
+ if (this.eventLogQuery.eventKey) {
|
|
|
+ params.eventKey = this.eventLogQuery.eventKey
|
|
|
+ }
|
|
|
|
|
|
-.attr-name {
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
+ const res = await listEventLog(params)
|
|
|
+ this.eventLogList = res.rows || []
|
|
|
+ this.eventLogTotal = res.total || 0
|
|
|
+ } catch (error) {
|
|
|
+ this.$message.error('查询事件日志失败')
|
|
|
+ } finally {
|
|
|
+ this.eventLogLoading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
|
|
|
+ // 重置事件日志查询
|
|
|
+ resetEventLogQuery() {
|
|
|
+ this.initDateRange()
|
|
|
+ this.eventLogQuery.eventKey = ''
|
|
|
+ this.eventLogQuery.pageNum = 1
|
|
|
+ this.queryEventLogs()
|
|
|
+ },
|
|
|
|
|
|
-.contents {
|
|
|
- border: 20px solid #f2f2f5;
|
|
|
- background-color: #f2f2f5;
|
|
|
-}
|
|
|
+ // 格式化调用状态
|
|
|
+ formatCallStatus(status) {
|
|
|
+ const statusMap = {
|
|
|
+ 0: '成功',
|
|
|
+ 1: '进行中',
|
|
|
+ 2: '失败'
|
|
|
+ }
|
|
|
+ return statusMap[status] || '未知'
|
|
|
+ },
|
|
|
|
|
|
+ // 获取调用状态类型
|
|
|
+ getCallStatusType(status) {
|
|
|
+ const typeMap = {
|
|
|
+ 0: 'success',
|
|
|
+ 1: 'warning',
|
|
|
+ 2: 'danger'
|
|
|
+ }
|
|
|
+ return typeMap[status] || 'info'
|
|
|
+ },
|
|
|
|
|
|
-.other-content {
|
|
|
- background-color: #ffffff; /* 白色背景 */
|
|
|
- padding: 20px;
|
|
|
- margin-bottom: 20px;
|
|
|
+ // 查看调用日志详情
|
|
|
+ async handleCallLogDetail(row) {
|
|
|
+ try {
|
|
|
+ const res = await getCallLog(row.id)
|
|
|
+ this.callLogDetailData = res.data
|
|
|
+ this.callLogDetailDialog = true
|
|
|
+ } catch (error) {
|
|
|
+ this.$message.error('获取调用日志详情失败')
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 查看事件日志详情
|
|
|
+ async handleEventLogDetail(row) {
|
|
|
+ try {
|
|
|
+ const res = await getEventLog(row.id)
|
|
|
+ this.eventLogDetailData = res.data
|
|
|
+ this.eventLogDetailDialog = true
|
|
|
+ } catch (error) {
|
|
|
+ this.$message.error('获取事件日志详情失败')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+</script>
|
|
|
|
|
|
-.table-content {
|
|
|
- background-color: #ffffff; /* 白色背景 */
|
|
|
+<style lang="scss" scoped>
|
|
|
+.app-container {
|
|
|
padding: 20px;
|
|
|
+ background: #f5f7fa;
|
|
|
+ min-height: calc(100vh - 84px);
|
|
|
}
|
|
|
|
|
|
-.pagination-container {
|
|
|
+.system-info-card {
|
|
|
margin-bottom: 20px;
|
|
|
-}
|
|
|
|
|
|
-.button-group-container {
|
|
|
- display: flex;
|
|
|
- justify-content: flex-end;
|
|
|
- min-width: 200px;
|
|
|
- padding: 5px;
|
|
|
-}
|
|
|
+ .card-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
|
|
|
-.device-list {
|
|
|
- margin-top: 20px;
|
|
|
-}
|
|
|
+ .title {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: bold;
|
|
|
|
|
|
-.device-card {
|
|
|
- background-color: #fff;
|
|
|
- border: 1px solid #bfcbd9;
|
|
|
- border-radius: 4px;
|
|
|
- overflow: hidden;
|
|
|
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
- transition: 0.3s;
|
|
|
- padding: 10px;
|
|
|
- font-size: 14px;
|
|
|
- height: 200px;
|
|
|
- margin-bottom: 20px;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
-}
|
|
|
+ i {
|
|
|
+ margin-right: 8px;
|
|
|
+ color: #409EFF;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-.device-header {
|
|
|
- //background-color: #f2f2f5;
|
|
|
- //padding: 10px;
|
|
|
- color: #545353;
|
|
|
- font-size: 20px;
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
+ .info-group {
|
|
|
+ .group-title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #606266;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ padding-bottom: 6px;
|
|
|
+ border-bottom: 1px solid #EBEEF5;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-.device-code {
|
|
|
- color: cornflowerblue;
|
|
|
-}
|
|
|
+ .info-item {
|
|
|
+ margin-bottom: 12px;
|
|
|
+ font-size: 14px;
|
|
|
|
|
|
-.deviceOthers {
|
|
|
- color: black;
|
|
|
-}
|
|
|
+ label {
|
|
|
+ color: #909399;
|
|
|
+ margin-right: 8px;
|
|
|
+ display: inline-block;
|
|
|
+ min-width: 80px;
|
|
|
+ }
|
|
|
|
|
|
-.device-body {
|
|
|
- padding: 10px;
|
|
|
- color: #666666;
|
|
|
- flex: 1; /* 使设备主体内容占据剩余空间 */
|
|
|
- overflow-y: auto; /* 如果内容过多,允许滚动 */
|
|
|
+ .code {
|
|
|
+ font-family: monospace;
|
|
|
+ color: #409EFF;
|
|
|
+ background: #f0f9ff;
|
|
|
+ padding: 2px 6px;
|
|
|
+ border-radius: 3px;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-.device-footer {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- padding: 5px;
|
|
|
- // background-color: #f9f9f9;
|
|
|
-}
|
|
|
+.detail-card {
|
|
|
+ .tab-content {
|
|
|
+ min-height: 400px;
|
|
|
+ }
|
|
|
|
|
|
-.device-footer .el-button {
|
|
|
- padding: 5px 15px;
|
|
|
- border: none; /* 移除默认边框 */
|
|
|
- color: #5a5e66;
|
|
|
- transition: background-color 0.3s; /* 平滑过渡背景色变化 */
|
|
|
-}
|
|
|
+ .attr-section {
|
|
|
+ margin-bottom: 30px;
|
|
|
|
|
|
-/* 为按钮分配不同的颜色 */
|
|
|
-.device-footer .el-button:first-child {
|
|
|
- background-color: #d5f1d5; /* 淡绿色 */
|
|
|
- border: 1px solid lightgreen;
|
|
|
- color: #71e2aa;
|
|
|
+ .section-title {
|
|
|
+ margin: 20px 0 15px 0;
|
|
|
+ color: #303133;
|
|
|
|
|
|
-}
|
|
|
+ i {
|
|
|
+ margin-right: 8px;
|
|
|
+ color: #409EFF;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-.device-footer .el-button:nth-child(2) {
|
|
|
- background-color: #ffe5b4; /* 淡橙色 */
|
|
|
- border: 1px solid #ffba00;
|
|
|
- color: #faad14;
|
|
|
-}
|
|
|
+ .url-text {
|
|
|
+ color: #409EFF;
|
|
|
+ font-family: monospace;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-.device-footer .el-button:last-child {
|
|
|
- background-color: #ffd5d5; /* 淡红色 */
|
|
|
- border: 1px solid lightpink;
|
|
|
- color: #f5222d;
|
|
|
-}
|
|
|
+ .device-stats {
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ .stat-item {
|
|
|
+ text-align: center;
|
|
|
+ padding: 20px;
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid #EBEEF5;
|
|
|
+ border-radius: 4px;
|
|
|
+
|
|
|
+ .stat-value {
|
|
|
+ font-size: 28px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #303133;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
|
|
|
-/* 鼠标悬停时加深颜色 */
|
|
|
-.device-footer .el-button:hover {
|
|
|
- filter: brightness(0.5); /* 颜色加深效果 */
|
|
|
-}
|
|
|
+ .stat-label {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #909399;
|
|
|
+ }
|
|
|
|
|
|
-/* 背景色样式 */
|
|
|
-.north {
|
|
|
- background: linear-gradient(to right, #e1f3d8, #fafafa);
|
|
|
-}
|
|
|
+ &.online .stat-value {
|
|
|
+ color: #67C23A;
|
|
|
+ }
|
|
|
|
|
|
-.south {
|
|
|
- background: linear-gradient(to right, #fff7e8, #fafafa);
|
|
|
-}
|
|
|
+ &.offline .stat-value {
|
|
|
+ color: #F56C6C;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-.main {
|
|
|
- background: linear-gradient(to right, #e0e0e0, #fafafa);
|
|
|
-}
|
|
|
+ .device-detail {
|
|
|
+ padding: 20px;
|
|
|
+ background: #f5f7fa;
|
|
|
|
|
|
+ h5 {
|
|
|
+ margin: 15px 0 10px 0;
|
|
|
+ color: #303133;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-.el-table {
|
|
|
- background-color: #ffffff; /* 白色背景 */
|
|
|
+ .log-filter {
|
|
|
+ margin-bottom: 20px;
|
|
|
+ padding: 15px;
|
|
|
+ background: #f5f7fa;
|
|
|
+ border-radius: 4px;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-.el-card {
|
|
|
- background-color: #ffffff; /* 白色背景 */
|
|
|
+.execute-result {
|
|
|
+ .result-data {
|
|
|
+ margin-top: 20px;
|
|
|
+
|
|
|
+ pre {
|
|
|
+ background: #f5f7fa;
|
|
|
+ padding: 15px;
|
|
|
+ border-radius: 4px;
|
|
|
+ overflow: auto;
|
|
|
+ max-height: 400px;
|
|
|
+ font-family: monospace;
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|