更新
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
import service from '@/utils/request'
|
||||
|
||||
// 网关
|
||||
export const getDeviceGatewayListByPage = (data) => {
|
||||
return service({
|
||||
url: '/device/getDeviceGatewayListByPage',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 设备
|
||||
export const getDeviceListByPage = (data) => {
|
||||
return service({
|
||||
url: '/device/getDeviceListByPage',
|
||||
@@ -15,7 +23,7 @@ export const deviceOperation = (data) => {
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 曲线
|
||||
export const getDeviceDetailsListByPage = (data) => {
|
||||
return service({
|
||||
url: '/device/getDeviceDetailsListByPage',
|
||||
@@ -23,3 +31,20 @@ export const getDeviceDetailsListByPage = (data) => {
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 报警
|
||||
export const getAlarmRecordListByPage = (data) => {
|
||||
return service({
|
||||
url: '/device/getAlarmRecordListByPage',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 报警
|
||||
export const getCircuitBreakerDetail = (data) => {
|
||||
return service({
|
||||
url: '/device/getCircuitBreakerDetail',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import service from '@/utils/request'
|
||||
|
||||
export const getDeviceDetailsListByPage = (data) => {
|
||||
return service({
|
||||
url: '/device/getDeviceDetailsListByPage',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
"/src/view/equipment/index.vue": "Equipment",
|
||||
"/src/view/equipment/list/components/detail/components/alarm/index.vue": "Index",
|
||||
"/src/view/equipment/list/components/detail/components/info/index.vue": "Index",
|
||||
"/src/view/equipment/list/components/detail/components/line/index.vue": "Index",
|
||||
"/src/view/equipment/list/components/detail/components/trend/index.vue": "Index",
|
||||
"/src/view/equipment/list/components/detail/index.vue": "Index",
|
||||
"/src/view/equipment/list/components/list/index.vue": "Index",
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
})
|
||||
if (table.code === 0) {
|
||||
tableData.value = table.data.list || []
|
||||
total.value = table.data.total || 0
|
||||
// total.value = table.data.total || 0
|
||||
return
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,79 +1,185 @@
|
||||
<template>
|
||||
<div class="detail-content">
|
||||
<div class="detail-card">
|
||||
<h3>基本信息</h3>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">设备ID:</span>
|
||||
<span class="detail-value">{{ device?.ID || '未设置' }}</span>
|
||||
<!-- <div class="cards">
|
||||
<div class="detail-card">
|
||||
<h3>基本信息</h3>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">设备号:</span>
|
||||
<span class="detail-value">{{ device?.gatewayId || '未设置' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">经度:</span>
|
||||
<span class="detail-value">{{ device?.gatewayLong || '未设置' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">纬度:</span>
|
||||
<span class="detail-value">{{ device?.gatewayLat || '未设置' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">imei:</span>
|
||||
<span class="detail-value">{{ device?.imei || '未设置' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">网关ID:</span>
|
||||
<span class="detail-value">{{ device?.gatewayId || '未设置' }}</span>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3>状态信息</h3>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">网络状态:</span>
|
||||
<span class="detail-value">
|
||||
<el-tag :type="device?.netStatus == 1 ? 'primary' : 'info'">
|
||||
{{ device?.netStatus == 1 ? '在线' : '离线' }}
|
||||
</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">设备类型名称:</span>
|
||||
<span class="detail-value">{{ device?.cbTypeName || '未设置' }}</span>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3>其他信息</h3>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">安装时间:</span>
|
||||
<span class="detail-value">{{ device?.createTime || '未设置' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">网关mac:</span>
|
||||
<span class="detail-value">{{ device?.gatewayMac || '未设置' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">协议:</span>
|
||||
<span class="detail-value">{{ device?.protocol || '未设置' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">品牌:</span>
|
||||
<span class="detail-value">{{ device?.brand || '未设置' }}</span>
|
||||
</div> -->
|
||||
<div class="info-box">
|
||||
<p class="title">基础信息</p>
|
||||
<div class="details">
|
||||
<el-image src="https://v5.snd02.com/upload/icon/UN2.png" style="width: 150px; height: 150px; cursor: pointer" />
|
||||
<div>
|
||||
<p>
|
||||
<span>设备号:</span>
|
||||
<span>{{ device?.gatewayId || '未设置' }}</span>
|
||||
</p>
|
||||
<p>
|
||||
<span>网络状态:</span>
|
||||
<span
|
||||
><el-tag :type="device?.netStatus == 1 ? 'primary' : 'info'">
|
||||
{{ device?.netStatus == 1 ? '在线' : '离线' }}
|
||||
</el-tag></span
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<span>经度:</span>
|
||||
<span>{{ device?.gatewayLong || '未设置' }}</span>
|
||||
</p>
|
||||
<p>
|
||||
<span>纬度:</span>
|
||||
<span>{{ device?.gatewayLat || '未设置' }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
<span>imei:</span>
|
||||
<span>{{ device?.imei || '未设置' }}</span>
|
||||
</p>
|
||||
<p>
|
||||
<span>地址:</span>
|
||||
<span>{{ device?.gatewayAddress || '未设置' }}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3>状态信息</h3>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">设备状态:</span>
|
||||
<span class="detail-value">
|
||||
<el-tag v-if="device?.cbTypeName !== 'T30'" :type="device?.deviceStatus == 1 ? 'success' : 'danger'">
|
||||
{{ device?.deviceStatus == 1 ? '合闸' : '分闸' }}
|
||||
</el-tag>
|
||||
<span v-else>-</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">锁定状态:</span>
|
||||
<span class="detail-value">
|
||||
<el-tag :type="['success', 'info', 'danger'][device?.lockStatus]">
|
||||
{{ ['正常', '远程合闸禁止', '锁定'][device?.lockStatus] }}
|
||||
</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">网络状态:</span>
|
||||
<span class="detail-value">
|
||||
<el-tag :type="device?.netStatus == 1 ? 'primary' : 'info'">
|
||||
{{ device?.netStatus == 1 ? '在线' : '离线' }}
|
||||
</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3>其他信息</h3>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">安装时间:</span>
|
||||
<span class="detail-value">{{ device?.createTime || '未设置' }}</span>
|
||||
<div class="alarms-box">
|
||||
<p class="title">报警列表</p>
|
||||
<div>
|
||||
<el-table :data="tableData" style="width: 100%" stripe>
|
||||
<el-table-column prop="CreatedAt" label="报警时间" width="180" />
|
||||
<el-table-column prop="type" label="报警类型" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="typeMap.find((item) => item.value == row.warnType)?.type || 'info'">{{
|
||||
typeMap.find((item) => item.value == row.warnType)?.label || row.warnType
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="level" label="报警等级" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="levelMap.find((item) => item.value == row.alarmLevel)?.type || 'info'" effect="dark">{{
|
||||
levelMap.find((item) => item.value == row.alarmLevel)?.label || row.alarmLevel
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="originalContent" label="报警描述">
|
||||
<template #default="{ row }">
|
||||
{{ row.remark || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
import { ref, onMounted } from 'vue'
|
||||
import * as serve from '@/api/equipment/list'
|
||||
const props = defineProps({
|
||||
device: {
|
||||
type: Object,
|
||||
default: () => null
|
||||
}
|
||||
})
|
||||
const typeMap = [
|
||||
{
|
||||
value: '45',
|
||||
type: 'danger',
|
||||
label: '设备事件'
|
||||
},
|
||||
{
|
||||
value: '4f',
|
||||
type: 'danger',
|
||||
label: '操作事件'
|
||||
}
|
||||
]
|
||||
const levelMap = [
|
||||
{
|
||||
value: '0',
|
||||
type: 'primary',
|
||||
label: '记录'
|
||||
},
|
||||
{
|
||||
value: '1',
|
||||
type: 'warning',
|
||||
label: '提醒'
|
||||
},
|
||||
{
|
||||
value: '2',
|
||||
type: 'danger',
|
||||
label: '警告'
|
||||
}
|
||||
]
|
||||
const params = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
sortBy: 'CreatedAt',
|
||||
desc: true
|
||||
})
|
||||
const tableData = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
// console.log('123123')
|
||||
// getAlarmRecordListByPage()
|
||||
getAlarmRecordListByPage()
|
||||
})
|
||||
|
||||
const getAlarmRecordListByPage = async () => {
|
||||
// console.log(123)
|
||||
const gatewayMac = props.device?.gatewayMac
|
||||
if (gatewayMac) {
|
||||
try {
|
||||
const table = await serve.getAlarmRecordListByPage({ gatewayMac, ...params.value })
|
||||
if (table.code === 0) {
|
||||
tableData.value = table.data.list || []
|
||||
// total.value = table.data.total || 0
|
||||
return
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取报警记录失败', e)
|
||||
}
|
||||
} else {
|
||||
console.warn('[Alarm] device 为空或没有 ID 字段')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -83,43 +189,94 @@
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
background-color: var(--el-bg-color-overlay, #ffffff);
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
border: 1px solid var(--el-border-color, #e4e7ed);
|
||||
// .cards {
|
||||
// display: flex;
|
||||
// // flex-direction: column;
|
||||
// gap: 5px;
|
||||
// }
|
||||
|
||||
h3 {
|
||||
// .detail-card {
|
||||
// background-color: var(--el-bg-color-overlay, #ffffff);
|
||||
// border-radius: 8px;
|
||||
// padding: 24px;
|
||||
// border: 1px solid var(--el-border-color, #e4e7ed);
|
||||
// flex: 1;
|
||||
// h3 {
|
||||
// font-size: 16px;
|
||||
// font-weight: 600;
|
||||
// color: var(--el-text-color-primary, #303133);
|
||||
// margin: 0 0 16px 0;
|
||||
// padding-bottom: 12px;
|
||||
// border-bottom: 1px solid var(--el-border-color-lighter, #ebeef5);
|
||||
// }
|
||||
// }
|
||||
|
||||
// .detail-row {
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// padding: 12px 0;
|
||||
// border-bottom: 1px dashed var(--el-border-color-lighter, #ebeef5);
|
||||
|
||||
// &:last-child {
|
||||
// border-bottom: none;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .detail-label {
|
||||
// width: 120px;
|
||||
// color: var(--el-text-color-regular, #606266);
|
||||
// font-size: 14px;
|
||||
// flex-shrink: 0;
|
||||
// }
|
||||
|
||||
// .detail-value {
|
||||
// flex: 1;
|
||||
// color: var(--el-text-color-primary, #303133);
|
||||
// font-size: 14px;
|
||||
// }
|
||||
.alarms-box,
|
||||
.info-box {
|
||||
@apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2 rounded-lg;
|
||||
padding-bottom: 40px;
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
margin: 0 0 16px 0;
|
||||
// margin: 0 0 16px 0;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--el-border-color-lighter, #ebeef5);
|
||||
// border-bottom: 1px solid var(--el-border-color-lighter, #ebeef5);
|
||||
}
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
.alarms-box {
|
||||
> div {
|
||||
margin-top: 15px;
|
||||
padding-left: 25px;
|
||||
}
|
||||
}
|
||||
.info-box .details {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px dashed var(--el-border-color-lighter, #ebeef5);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
margin-top: 15px;
|
||||
padding-left: 25px;
|
||||
// flex-direction: column;
|
||||
gap: 40px;
|
||||
> div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 30%;
|
||||
gap: 20px;
|
||||
> p {
|
||||
> span {
|
||||
font-size: 14px;
|
||||
&:nth-child(1) {
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-regular, #606266);
|
||||
}
|
||||
&:nth-child(2) {
|
||||
color: var(--el-text-color-regular, #303133);
|
||||
}
|
||||
}
|
||||
}
|
||||
// justify-content: space-around;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
width: 120px;
|
||||
color: var(--el-text-color-regular, #606266);
|
||||
font-size: 14px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
flex: 1;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<div class="line-content">
|
||||
<div class="detail-card">
|
||||
<h3>线路列表</h3>
|
||||
<el-table :data="tableData" style="width: 100%" height="400" stripe>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="lineName" label="线路名称" width="120">
|
||||
<template #default="{ row }">
|
||||
{{ row.nodeNumber == 0 ? '总路' : `线路${row.nodeNumber}` }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="lineCode" label="接线方式" width="120">
|
||||
<template #default="{ row }">
|
||||
{{ row.nodeNumber == 0 ? '进线直连' : '总路' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="nodeNumber" label="地址码" width="120" />
|
||||
|
||||
<el-table-column prop="status" label="状态" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.deviceStatus === 1 ? 'danger' : 'success'">
|
||||
{{ row.deviceStatus === 1 ? '合闸' : '分闸' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="['success', 'info', 'danger'][row.lockStatus]">
|
||||
{{ ['正常', '远程合闸禁止', '锁定'][row.lockStatus] }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" />
|
||||
<el-table-column label="操作" :min-width="appStore.operateMinWith" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.deviceStatus == 1" type="success" link icon="SortUp" @click="changeStatus(row)"
|
||||
>分闸</el-button
|
||||
>
|
||||
<el-button v-else type="danger" link icon="SortDown" @click="changeStatus(row)">合闸</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as serve from '@/api/equipment/list.js'
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
|
||||
import { useAppStore } from '@/pinia'
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const props = defineProps({
|
||||
device: {
|
||||
type: Object,
|
||||
default: () => null
|
||||
}
|
||||
})
|
||||
|
||||
const tableData = ref([])
|
||||
|
||||
const params = ref({
|
||||
page: 1,
|
||||
pageSize: 50,
|
||||
sortBy: 'CreatedAt',
|
||||
desc: true
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getDeviceListByPage()
|
||||
})
|
||||
|
||||
const getDeviceListByPage = async () => {
|
||||
const gatewayMac = props.device?.gatewayMac
|
||||
if (gatewayMac) {
|
||||
try {
|
||||
const res = await serve.getDeviceListByPage({
|
||||
gatewayMac,
|
||||
...params.value
|
||||
})
|
||||
if (res.code === 0) {
|
||||
tableData.value = res.data.list || []
|
||||
// total.value = res.data.total || 0
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取线路列表失败', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 合分闸
|
||||
const changeStatus = (row) => {
|
||||
ElMessageBox.confirm(row.deviceStatus == 1 ? '确认分闸吗?' : '确认合闸吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
const res = await serve.deviceOperation({
|
||||
id: row.ID,
|
||||
gatewayId: row.gatewayId,
|
||||
para: row.deviceStatus == 1 ? '0xA2' : '0xA1'
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('操作成功')
|
||||
getDeviceListByPage()
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.detail-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
background-color: var(--el-bg-color-overlay, #ffffff);
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
border: 1px solid var(--el-border-color, #e4e7ed);
|
||||
|
||||
h3 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
margin: 0 0 16px 0;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--el-border-color-lighter, #ebeef5);
|
||||
}
|
||||
}
|
||||
|
||||
.gva-pagination {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div ref="chartContainerRef" class="trend-content">
|
||||
<div class="trend-toolbar">
|
||||
<!-- <div class="trend-toolbar">
|
||||
<span class="toolbar-label">时间范围:</span>
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
@@ -12,31 +12,140 @@
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
@change="handleDateChange"
|
||||
/>
|
||||
<!-- <el-button type="primary" icon="Refresh" @click="resetDateRange">重置</el-button> -->
|
||||
</div>
|
||||
<el-row v-if="isReady" :gutter="16">
|
||||
<el-col v-for="(item, index) in chartList" :key="item.key" :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
|
||||
<div class="chart-card">
|
||||
<div class="chart-header">
|
||||
<span class="chart-title">{{ item.title }}</span>
|
||||
<span class="chart-unit">{{ item.unit }}</span>
|
||||
|
||||
</div> -->
|
||||
|
||||
<div class="left">
|
||||
<div class="title">
|
||||
<span>线路列表</span>
|
||||
<el-button :disabled="!checkedDevices.length" plain size="small" type="success">一键分闸</el-button>
|
||||
<el-button style="margin-left: 3px" :disabled="!checkedDevices.length" plain size="small" type="danger"
|
||||
>一键合闸</el-button
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange">
|
||||
全选
|
||||
</el-checkbox>
|
||||
<el-checkbox-group v-model="checkedDevices" @change="handleCheckedDevicesChange">
|
||||
<div
|
||||
class="ouliy"
|
||||
:class="{ active: currentCheck == index }"
|
||||
v-for="(item, index) in deviceList"
|
||||
:key="item.id"
|
||||
>
|
||||
<el-checkbox :value="item.id">
|
||||
<div class="line-item" @click.stop.prevent="handleClick(item, index)">
|
||||
<span>{{ item.nodeNumber == 0 ? '总路' : `线路${index + 1}` }}</span>
|
||||
<span>{{ `(${item.gatewayMac})` }}</span>
|
||||
<el-tag v-if="item.status == 1" type="danger" size="small" effect="light"> 合闸 </el-tag>
|
||||
<el-tag v-else type="success" size="small" effect="light"> 分闸 </el-tag>
|
||||
</div>
|
||||
</el-checkbox>
|
||||
</div>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="top">
|
||||
<p class="title">基本信息</p>
|
||||
<div class="info">
|
||||
<div class="item">
|
||||
<div>
|
||||
<span>设备名称:</span>
|
||||
<span>{{
|
||||
circuitBreaker.device?.nodeNumber == 0 ? '总路' : `线路${circuitBreaker.device?.nodeNumber}`
|
||||
}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>线路ID:</span>
|
||||
<span>{{ `${circuitBreaker.device?.gatewayMac}-${circuitBreaker.device?.nodeNumber}` }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>总功率:</span>
|
||||
<span>{{ circuitBreaker.latestTelemetry?.power || 0 }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>机身温度(℃):</span>
|
||||
<span>{{ circuitBreaker.latestTelemetry?.internalTemperature || 0 }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>漏保档位:</span>
|
||||
<span>无</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>电气子节点:</span>
|
||||
<span>点击展开</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>警情状态:</span>
|
||||
<span>--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div>
|
||||
<span>线路状态:</span>
|
||||
<span
|
||||
><el-tag v-if="circuitBreaker.device?.deviceStatus == 1" type="danger" size="small" effect="light">
|
||||
合闸
|
||||
</el-tag>
|
||||
<el-tag v-else type="success" size="small" effect="light"> 分闸 </el-tag></span
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<span>地址码:</span>
|
||||
<span>{{ circuitBreaker.latestTelemetry?.nodeNumber || '--' }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>环境温度:</span>
|
||||
<span>--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="other" style="width: 100%">
|
||||
<div>
|
||||
<el-button :disabled="circuitBreaker.device?.deviceStatus == 1" type="danger" plain @click="changeStatus"
|
||||
>合闸</el-button
|
||||
>
|
||||
<el-button :disabled="circuitBreaker.device?.deviceStatus == 0" type="success" plain @click="changeStatus"
|
||||
>分闸</el-button
|
||||
>
|
||||
</div>
|
||||
<el-table :data="realTimeData" border>
|
||||
<el-table-column prop="text" label="实时数据" />
|
||||
<el-table-column prop="value" label="相线" />
|
||||
</el-table>
|
||||
</div>
|
||||
<v-chart class="chart" :option="item.option" autoresize />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div>
|
||||
<p class="title">运行趋势</p>
|
||||
</div>
|
||||
<el-row v-if="isReady">
|
||||
<el-col v-for="(item, index) in chartList" :key="item.key" :span="24">
|
||||
<div class="chart-card">
|
||||
<div class="chart-header">
|
||||
<span class="chart-title">{{ item.title }}</span>
|
||||
<span class="chart-unit">{{ item.unit }}</span>
|
||||
</div>
|
||||
<v-chart class="chart" :option="item.option" autoresize />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as serve from '@/api/equipment/list.js'
|
||||
import { ref, nextTick, onMounted, onBeforeUnmount, watch } from 'vue'
|
||||
import { use } from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
import { LineChart } from 'echarts/charts'
|
||||
import { TitleComponent, TooltipComponent, LegendComponent, GridComponent } from 'echarts/components'
|
||||
import VChart from 'vue-echarts'
|
||||
import * as serve from '@/api/equipment/list.js'
|
||||
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
use([CanvasRenderer, LineChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent])
|
||||
|
||||
const props = defineProps({
|
||||
@@ -46,12 +155,55 @@
|
||||
}
|
||||
})
|
||||
|
||||
const currentCheck = ref(0)
|
||||
|
||||
const deviceList = ref([])
|
||||
// const circuitBreaker = ref({})
|
||||
|
||||
const handleClick = (item, index) => {
|
||||
currentCheck.value = index
|
||||
console.log(item, index)
|
||||
|
||||
getDeviceDetailsListByPage()
|
||||
getCircuitBreakerDetail()
|
||||
}
|
||||
// 容器 ref
|
||||
const chartContainerRef = ref(null)
|
||||
// 容器就绪状态:父级用 v-show 切换时,初始为 display:None,宽度为 0,需要等容器有尺寸后再渲染图表
|
||||
const isReady = ref(false)
|
||||
let resizeObserver = null
|
||||
|
||||
onMounted(async () => {
|
||||
if (chartContainerRef.value) {
|
||||
nextTick(checkContainerReady)
|
||||
resizeObserver = new ResizeObserver(() => {
|
||||
checkContainerReady()
|
||||
})
|
||||
resizeObserver.observe(chartContainerRef.value)
|
||||
}
|
||||
await getDeviceListByPage()
|
||||
getCircuitBreakerDetail()
|
||||
getDeviceDetailsListByPage()
|
||||
})
|
||||
|
||||
// 左侧设备(线路)列表
|
||||
const getDeviceListByPage = async () => {
|
||||
const gatewayMac = props.device?.gatewayMac
|
||||
if (gatewayMac) {
|
||||
const res = await serve.getDeviceListByPage({
|
||||
gatewayMac,
|
||||
page: 1,
|
||||
pageSize: 50,
|
||||
sortBy: 'CreatedAt',
|
||||
desc: true
|
||||
})
|
||||
if (res.code === 0) {
|
||||
deviceList.value = res.data.list || []
|
||||
// total.value = res.data.total || 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检测容器是否已具备尺寸
|
||||
const checkContainerReady = () => {
|
||||
if (isReady.value || !chartContainerRef.value) return
|
||||
@@ -88,25 +240,41 @@
|
||||
}
|
||||
return ''
|
||||
}
|
||||
const circuitBreaker = ref([])
|
||||
const realTimeData = ref([])
|
||||
|
||||
const getTableData = async () => {
|
||||
// 如果没有 device 或 ID,不请求
|
||||
if (!props.device) {
|
||||
console.warn('[Trend] device 为空,跳过请求')
|
||||
return
|
||||
}
|
||||
const deviceId = props.device.ID || props.device.id
|
||||
if (!deviceId) {
|
||||
console.warn('[Trend] device 没有 ID 字段')
|
||||
return
|
||||
// 基本信息
|
||||
const getCircuitBreakerDetail = async () => {
|
||||
const ID = deviceList.value[currentCheck.value].ID
|
||||
// console.log(deviceId)
|
||||
const res = await serve.getCircuitBreakerDetail({
|
||||
ID
|
||||
})
|
||||
if (res.code === 0) {
|
||||
const arr = [
|
||||
{ label: 'current', text: '电流(A)' },
|
||||
{ label: 'voltage', text: '电压' },
|
||||
{ label: 'internalTemperature', text: '温度' },
|
||||
{ label: 'powerFactor', text: '功率' }
|
||||
]
|
||||
if (res.data.latestTelemetry) {
|
||||
arr.forEach((item) => {
|
||||
item.value = res.data.latestTelemetry[item.label] || '--'
|
||||
})
|
||||
realTimeData.value = arr
|
||||
}
|
||||
|
||||
circuitBreaker.value = res.data
|
||||
console.log('circuitBreaker', circuitBreaker.value)
|
||||
}
|
||||
}
|
||||
// echarts图
|
||||
const getDeviceDetailsListByPage = async () => {
|
||||
if (!dateRange.value || dateRange.value.length !== 2) {
|
||||
console.warn('[Trend] 日期范围无效')
|
||||
return
|
||||
}
|
||||
// 格式化时间
|
||||
// const startTime = formatDateTime(dateRange.value[0])
|
||||
// const endTime = formatDateTime(dateRange.value[1])
|
||||
const deviceId = deviceList.value[currentCheck.value].id
|
||||
try {
|
||||
const result = await serve.getDeviceDetailsListByPage({
|
||||
page: 1,
|
||||
@@ -119,12 +287,8 @@
|
||||
order: 'desc',
|
||||
desc: true
|
||||
})
|
||||
|
||||
if (result.code === 0) {
|
||||
// 提取数据
|
||||
const list = result.data.list || []
|
||||
// 调试:打印第一条数据的所有字段
|
||||
|
||||
const timeData = []
|
||||
const chartData = {
|
||||
voltage: [], // 电压(V)
|
||||
@@ -137,7 +301,6 @@
|
||||
|
||||
list.forEach((item) => {
|
||||
timeData.push(item.CreatedAt)
|
||||
// 兼容多种命名风格:PascalCase / camelCase
|
||||
chartData.voltage.push(item.voltage)
|
||||
chartData.leakageCurrent.push(item.leakageCurrent)
|
||||
chartData.cumulativeElectricity.push(item.cumulativeElectricity)
|
||||
@@ -145,42 +308,24 @@
|
||||
chartData.internalTemperature.push(item.internalTemperature)
|
||||
chartData.powerFactor.push(item.powerFactor)
|
||||
})
|
||||
console.log('[Trend] X轴时间数据:', timeData)
|
||||
console.log('[Trend] 处理后的图表数据:', chartData)
|
||||
// 更新图表
|
||||
updateChartData(timeData, chartData)
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 监听 device 变化,重新请求数据
|
||||
watch(
|
||||
() => props.device,
|
||||
(newDevice, oldDevice) => {
|
||||
if (newDevice && (!oldDevice || newDevice.ID !== oldDevice.ID)) {
|
||||
getTableData()
|
||||
}
|
||||
nextTick(() => {
|
||||
triggerResize()
|
||||
})
|
||||
},
|
||||
{ deep: true, immediate: false }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
// 父级用 v-show 切换 Tab,组件挂载时可能是 display:None(尺寸为 0),
|
||||
// 需要等容器有实际尺寸后再渲染 v-chart,否则 ECharts 初始化时会报
|
||||
// "Can't get DOM width or height"
|
||||
if (chartContainerRef.value) {
|
||||
// 先检查一次(处理初始就是可见的情况)
|
||||
nextTick(checkContainerReady)
|
||||
// 监听容器尺寸变化:从 0 变为有尺寸时(例如切到当前 Tab)触发 isReady
|
||||
resizeObserver = new ResizeObserver(() => {
|
||||
checkContainerReady()
|
||||
})
|
||||
resizeObserver.observe(chartContainerRef.value)
|
||||
}
|
||||
})
|
||||
// watch(
|
||||
// () => props.device,
|
||||
// (newDevice, oldDevice) => {
|
||||
// if (newDevice && (!oldDevice || newDevice.ID !== oldDevice.ID)) {
|
||||
// getDeviceDetailsListByPage()
|
||||
// }
|
||||
// nextTick(() => {
|
||||
// triggerResize()
|
||||
// })
|
||||
// },
|
||||
// { deep: true, immediate: false }
|
||||
// )
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (resizeObserver) {
|
||||
@@ -204,29 +349,11 @@
|
||||
// 触发图表 resize
|
||||
nextTick(() => {
|
||||
// triggerResize()
|
||||
getTableData()
|
||||
getDeviceDetailsListByPage()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 重置日期
|
||||
const resetDateRange = () => {
|
||||
dateRange.value = []
|
||||
|
||||
nextTick(() => {
|
||||
triggerResize()
|
||||
})
|
||||
}
|
||||
|
||||
// 生成模拟数据
|
||||
const generateMockData = () => {
|
||||
const hours = []
|
||||
for (let i = 0; i < 24; i++) {
|
||||
hours.push(`${i}:00`)
|
||||
}
|
||||
return hours
|
||||
}
|
||||
|
||||
// 基础折线图配置
|
||||
// data: 数据数组,xAxis: X 轴数据(可选)
|
||||
const createLineOption = (name, color, data = [], xAxis = []) => {
|
||||
@@ -243,7 +370,7 @@
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: xAxis.length ? xAxis : generateMockData(),
|
||||
data: xAxis,
|
||||
boundaryGap: false,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
@@ -343,6 +470,30 @@
|
||||
}
|
||||
])
|
||||
|
||||
// 合分闸
|
||||
const changeStatus = () => {
|
||||
const row = circuitBreaker.value.device || {}
|
||||
if (!row.ID) {
|
||||
ElMessage.error('请选择设备')
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm(row.deviceStatus == 1 ? '确认分闸吗?' : '确认合闸吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
const res = await serve.deviceOperation({
|
||||
id: row.ID,
|
||||
gatewayId: row.gatewayId,
|
||||
para: row.deviceStatus == 1 ? '0xA2' : '0xA1'
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('操作成功')
|
||||
getDeviceGatewayListByPage()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 更新图表数据
|
||||
const updateChartData = (timeData, chartData) => {
|
||||
chartList.value.forEach((item) => {
|
||||
@@ -350,11 +501,125 @@
|
||||
item.option = createLineOption(item.title, item.color, seriesData, timeData)
|
||||
})
|
||||
}
|
||||
// 多选
|
||||
const checkAll = ref(false)
|
||||
const isIndeterminate = ref(false)
|
||||
const checkedDevices = ref([])
|
||||
const handleCheckAllChange = (val) => {
|
||||
checkedDevices.value = val ? deviceList.value.map((item) => item.id) : []
|
||||
isIndeterminate.value = false
|
||||
}
|
||||
const handleCheckedDevicesChange = (value) => {
|
||||
const checkedCount = value.length
|
||||
checkAll.value = checkedCount === deviceList.value.length
|
||||
isIndeterminate.value = checkedCount > 0 && checkedCount < deviceList.value.length
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.trend-content {
|
||||
padding: 0;
|
||||
// @apply text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2 rounded-lg
|
||||
display: flex;
|
||||
|
||||
// flex-direction: column;
|
||||
gap: 10px;
|
||||
box-sizing: border-box;
|
||||
.left {
|
||||
@apply bg-white p-4 text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded rounded-lg
|
||||
width: 270px;
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
> span {
|
||||
margin-right: 50px;
|
||||
}
|
||||
// margin: 0 0 16px 0;
|
||||
// padding-bottom: 12px;
|
||||
// border-bottom: 1px solid var(--el-border-color-lighter, #ebeef5);
|
||||
}
|
||||
.line-item {
|
||||
> span {
|
||||
&:nth-child(1) {
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
display: inline-block;
|
||||
width: 140px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ouliy {
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
&.active {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--el-color-primary-light-8);
|
||||
}
|
||||
}
|
||||
}
|
||||
.right {
|
||||
height: calc(100vh - 6rem - 120px);
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
.top {
|
||||
@apply bg-white p-4 text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded rounded-lg;
|
||||
margin-bottom: 10px;
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
}
|
||||
.info {
|
||||
display: flex;
|
||||
// flex-direction: column;
|
||||
gap: 100px;
|
||||
}
|
||||
.item {
|
||||
padding: 12px 12px 0 12px;
|
||||
> div {
|
||||
height: 30px;
|
||||
white-space: nowrap;
|
||||
> span {
|
||||
&:nth-child(1) {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-regular, #ddd);
|
||||
}
|
||||
&:nth-child(2) {
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.other {
|
||||
:deep(.el-table .el-table__cell) {
|
||||
padding: 2px;
|
||||
}
|
||||
div {
|
||||
&:nth-child(1) {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.bottom {
|
||||
@apply bg-white p-4 text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded rounded-lg;
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.trend-toolbar {
|
||||
@@ -379,7 +644,6 @@
|
||||
background-color: var(--el-bg-color-overlay, #ffffff);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
border: 1px solid var(--el-border-color, #e4e7ed);
|
||||
margin-bottom: 16px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
|
||||
@@ -1,25 +1,36 @@
|
||||
<template>
|
||||
<div class="device-detail-page">
|
||||
<div class="detail-header">
|
||||
<!-- <div class="detail-header">
|
||||
<el-button icon="ArrowLeft" circle @click="handleBack" />
|
||||
<span class="detail-title">设备信息</span>
|
||||
</div> -->
|
||||
<div class="tabs-box">
|
||||
<el-button icon="ArrowLeft" circle @click="handleBack" />
|
||||
<span class="title">设备信息({{ device?.gatewayMac }})</span>
|
||||
<el-radio-group v-model="activeMenu" size="large" fill="#409eff">
|
||||
<el-radio-button label="设备详情" value="info" />
|
||||
<el-radio-button label="线路列表" value="line" />
|
||||
<el-radio-button label="运行趋势" value="trend" />
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
<el-menu :default-active="activeMenu" mode="horizontal" class="detail-menu" @select="handleMenuSelect">
|
||||
<!-- <el-menu :default-active="activeMenu" mode="horizontal" class="detail-menu" @select="handleMenuSelect">
|
||||
<el-menu-item index="info">设备详情</el-menu-item>
|
||||
<el-menu-item index="alarm">报警记录</el-menu-item>
|
||||
<el-menu-item index="trend">历史曲线</el-menu-item>
|
||||
</el-menu>
|
||||
</el-menu> -->
|
||||
|
||||
<DeviceInfo v-show="activeMenu === 'info'" :device="device" />
|
||||
<DeviceTrend v-show="activeMenu === 'trend'" :device="device" />
|
||||
<DeviceAlarm v-show="activeMenu === 'alarm'" :device="device" />
|
||||
<DeviceInfo v-if="activeMenu === 'info'" :device="device" />
|
||||
<DeviceLine v-if="activeMenu === 'line'" :device="device" />
|
||||
<DeviceTrend v-if="activeMenu === 'trend'" :device="device" />
|
||||
<!-- <DeviceAlarm v-show="activeMenu === 'alarm'" :device="device" /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import DeviceInfo from './components/info/index.vue'
|
||||
import DeviceLine from './components/line/index.vue'
|
||||
import DeviceTrend from './components/trend/index.vue'
|
||||
import DeviceAlarm from './components/alarm/index.vue'
|
||||
|
||||
@@ -30,23 +41,36 @@
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['back'])
|
||||
|
||||
const activeMenu = ref('info')
|
||||
|
||||
const handleMenuSelect = (index) => {
|
||||
activeMenu.value = index
|
||||
}
|
||||
const emit = defineEmits(['back'])
|
||||
|
||||
// const activeMenu = ref('info')
|
||||
|
||||
// const handleMenuSelect = (index) => {
|
||||
// activeMenu.value = index
|
||||
// }
|
||||
|
||||
const handleBack = () => {
|
||||
activeMenu.value = 'info'
|
||||
activeMenu.value = ''
|
||||
emit('back')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.device-detail-page {
|
||||
padding: 20px;
|
||||
// padding: 20px;
|
||||
.tabs-box {
|
||||
@apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2 rounded-lg;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
> .title {
|
||||
margin: 0 15px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
@@ -56,12 +80,6 @@
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.detail-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
}
|
||||
|
||||
.detail-menu {
|
||||
margin-bottom: 20px;
|
||||
// border-radius: 8px;
|
||||
|
||||
@@ -2,22 +2,10 @@
|
||||
<div>
|
||||
<div class="gva-search-box">
|
||||
<el-form ref="searchForm" :inline="true" :model="searchInfo">
|
||||
<el-form-item label="设备ID">
|
||||
<el-input v-model="searchInfo.ID" placeholder="请输入" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="设备状态">
|
||||
<el-select v-model="searchInfo.deviceStatus" clearable placeholder="请选择">
|
||||
<el-option label="合闸" :value="1" />
|
||||
<el-option label="分闸" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="协议">
|
||||
<el-select v-model="searchInfo.protocol" clearable placeholder="请选择">
|
||||
<el-option label="HTTP" value="HTTP" />
|
||||
<el-option label="UDP" value="UDP" />
|
||||
<el-option label="HEX" value="HEX" />
|
||||
</el-select>
|
||||
<el-form-item label="网关MAC">
|
||||
<el-input v-model="searchInfo.gatewayMac" placeholder="请输入" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="search" @click="onSubmit"> 查询 </el-button>
|
||||
<el-button icon="refresh" @click="onReset"> 重置 </el-button>
|
||||
@@ -32,9 +20,9 @@
|
||||
<div v-for="item in tableData" :key="item.ID" class="device-card" @click="handleCardClick(item, $event)">
|
||||
<div class="device-image">
|
||||
<img src="@/assets/img/equipment/breaker.png" alt="设备" />
|
||||
<div class="signal-icon" :class="{ online: item.netStatus == 1 }">
|
||||
<!-- <div class="signal-icon" :class="{ online: item.netStatus == 1 }">
|
||||
<i class="el-icon-connection"></i>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="device-info">
|
||||
<div class="card-menu">
|
||||
@@ -44,9 +32,9 @@
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="item.deviceStatus == 1" command="changeStatus">分闸</el-dropdown-item>
|
||||
<!-- <el-dropdown-item v-if="item.deviceStatus == 1" command="changeStatus">分闸</el-dropdown-item>
|
||||
<el-dropdown-item v-else command="changeStatus">分闸</el-dropdown-item>
|
||||
<el-dropdown-item v-if="[1].includes(item.lockStatus)" command="unlock">解锁</el-dropdown-item>
|
||||
<el-dropdown-item v-if="[1].includes(item.lockStatus)" command="unlock">解锁</el-dropdown-item> -->
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@@ -55,29 +43,39 @@
|
||||
<el-tag :type="item.netStatus == 1 ? 'primary' : 'info'">
|
||||
{{ item.netStatus == 1 ? '在线' : '离线' }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
<!-- <el-tag
|
||||
v-if="item.cbTypeName !== 'T30' && item.deviceStatus != 1"
|
||||
:type="item.deviceStatus == 1 ? 'success' : 'danger'"
|
||||
>
|
||||
{{ item.deviceStatus == 1 ? '合闸' : '分闸' }}
|
||||
</el-tag>
|
||||
<el-tag v-if="item.lockStatus != 0" :type="['success', 'info', 'danger'][item.lockStatus]">
|
||||
</el-tag> -->
|
||||
<!-- <el-tag v-if="item.lockStatus != 0" :type="['success', 'info', 'danger'][item.lockStatus]">
|
||||
{{ ['正常', '远程合闸禁止', '锁定'][item.lockStatus] }}
|
||||
</el-tag>
|
||||
</el-tag> -->
|
||||
</div>
|
||||
<div class="device-name">{{ item.cbTypeName }}</div>
|
||||
<div class="device-name">{{ item.gatewayMac }}</div>
|
||||
<div class="device-id-row">
|
||||
<span class="device-id">ID:{{ item.ID }}</span>
|
||||
<el-button size="small" type="primary" link icon="CopyDocument" @click.stop="copyDeviceId(item.ID)">
|
||||
<span class="device-id">ID:{{ item.gatewayId }}</span>
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
link
|
||||
icon="CopyDocument"
|
||||
@click.stop="copyDeviceId(item.gatewayId)"
|
||||
>
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="device-location">
|
||||
<el-icon><LocationInformation /></el-icon>
|
||||
<span>{{ item.gatewayMac }}</span>
|
||||
<span style="white-space: break-spaces">{{ item.gatewayAddress }}</span>
|
||||
</div>
|
||||
<div class="device-channels">
|
||||
<el-icon><Postcard /></el-icon>
|
||||
<span>{{ item.brand }}</span>
|
||||
<el-icon><Operation /></el-icon>
|
||||
<span>{{ '3' }}</span>
|
||||
</div>
|
||||
<div v-if="item.alarmType" class="device-alarm">
|
||||
<el-icon style="color: #f56c6c"><WarningFilled /></el-icon>
|
||||
<span style="color: #f56c6c">{{ item.alarmCreatedAt }} {{ item.alarmType }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -113,9 +111,7 @@
|
||||
const emit = defineEmits(['select-device'])
|
||||
|
||||
const searchInfo = ref({
|
||||
deviceStatus: '',
|
||||
protocol: '',
|
||||
ID: ''
|
||||
gatewayMac: ''
|
||||
})
|
||||
|
||||
const page = ref(1)
|
||||
@@ -124,7 +120,7 @@
|
||||
const tableData = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
getTableData()
|
||||
getDeviceGatewayListByPage()
|
||||
})
|
||||
|
||||
// 点击设备卡片
|
||||
@@ -154,7 +150,7 @@
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('操作成功')
|
||||
getTableData()
|
||||
getDeviceGatewayListByPage()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -173,7 +169,7 @@
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('操作成功')
|
||||
getTableData()
|
||||
getDeviceGatewayListByPage()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -181,15 +177,15 @@
|
||||
// 分页
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val
|
||||
getTableData()
|
||||
getDeviceGatewayListByPage()
|
||||
}
|
||||
const handleCurrentChange = (val) => {
|
||||
page.value = val
|
||||
getTableData()
|
||||
getDeviceGatewayListByPage()
|
||||
}
|
||||
// 查询
|
||||
const getTableData = async () => {
|
||||
const table = await serve.getDeviceListByPage({
|
||||
const getDeviceGatewayListByPage = async () => {
|
||||
const table = await serve.getDeviceGatewayListByPage({
|
||||
page: page.value,
|
||||
pageSize: pageSize.value,
|
||||
...searchInfo.value
|
||||
@@ -204,16 +200,14 @@
|
||||
|
||||
const onSubmit = () => {
|
||||
page.value = 1
|
||||
getTableData()
|
||||
getDeviceGatewayListByPage()
|
||||
}
|
||||
|
||||
const onReset = () => {
|
||||
searchInfo.value = {
|
||||
deviceStatus: '',
|
||||
protocol: '',
|
||||
ID: ''
|
||||
gatewayMac: ''
|
||||
}
|
||||
getTableData()
|
||||
getDeviceGatewayListByPage()
|
||||
}
|
||||
|
||||
// 复制设备ID
|
||||
@@ -249,7 +243,7 @@
|
||||
|
||||
.device-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
grid-template-columns: repeat(auto-fill, minmax(330px, 1fr));
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
background-color: var(--el-bg-color, #f5f7fa);
|
||||
@@ -309,7 +303,7 @@
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
position: relative;
|
||||
padding-right: 20px;
|
||||
// padding-right: 20px;
|
||||
}
|
||||
|
||||
.card-menu {
|
||||
@@ -347,14 +341,15 @@
|
||||
|
||||
.device-id {
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
color: var(--el-color-primary, #409eff);
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.device-location,
|
||||
.device-channels {
|
||||
.device-channels,
|
||||
.device-alarm {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
@@ -372,4 +367,11 @@
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
// .device-alarm {
|
||||
// display: flex;
|
||||
// // align-items: center;
|
||||
// gap: 4px;
|
||||
// font-size: 12px;
|
||||
// color: var(--el-text-color-regular, #606266);
|
||||
// }
|
||||
</style>
|
||||
|
||||
@@ -81,7 +81,8 @@
|
||||
nextTick(() => {
|
||||
document.getElementsByClassName(
|
||||
'flex flex-col md:flex-row gap-2 items-center text-sm text-slate-700 dark:text-slate-500 justify-center py-2'
|
||||
)[0].style.opacity = 0
|
||||
)[0].style.display = 'none'
|
||||
// opacity = 0
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user