|
@@ -79,7 +79,7 @@
|
|
|
</el-tab-pane>
|
|
</el-tab-pane>
|
|
|
|
|
|
|
|
<!-- 设备详情弹窗 -->
|
|
<!-- 设备详情弹窗 -->
|
|
|
- <el-dialog v-model="showDeviceDetail" :title="'设备详情 - ' + (selectedDevice?.name || '')" width="960px" top="5vh" @closed="handleCloseDetail">
|
|
|
|
|
|
|
+ <el-dialog v-model="showDeviceDetail" :title="'设备详情 - ' + (selectedDevice?.name || '')" width="1100px" top="5vh" class="device-detail-dialog" @closed="handleCloseDetail">
|
|
|
<div class="device-detail-body" v-if="selectedDevice">
|
|
<div class="device-detail-body" v-if="selectedDevice">
|
|
|
<div class="detail-top-row">
|
|
<div class="detail-top-row">
|
|
|
<div class="detail-info-section">
|
|
<div class="detail-info-section">
|
|
@@ -93,6 +93,10 @@
|
|
|
<span class="info-label">设备名称</span>
|
|
<span class="info-label">设备名称</span>
|
|
|
<span class="info-value">{{ selectedDevice.name }}</span>
|
|
<span class="info-value">{{ selectedDevice.name }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <div class="info-item">
|
|
|
|
|
+ <span class="info-label">设备品牌</span>
|
|
|
|
|
+ <span class="info-value">{{ selectedDevice.brand }}</span>
|
|
|
|
|
+ </div>
|
|
|
<div class="info-item">
|
|
<div class="info-item">
|
|
|
<span class="info-label">设备分类</span>
|
|
<span class="info-label">设备分类</span>
|
|
|
<span class="info-value">{{ selectedDevice.category }}</span>
|
|
<span class="info-value">{{ selectedDevice.category }}</span>
|
|
@@ -109,6 +113,10 @@
|
|
|
<span class="info-label">安装日期</span>
|
|
<span class="info-label">安装日期</span>
|
|
|
<span class="info-value">{{ selectedDevice.installDate }}</span>
|
|
<span class="info-value">{{ selectedDevice.installDate }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <div class="info-item">
|
|
|
|
|
+ <span class="info-label">安装人员</span>
|
|
|
|
|
+ <span class="info-value">{{ selectedDevice.installer }}</span>
|
|
|
|
|
+ </div>
|
|
|
<div class="info-item">
|
|
<div class="info-item">
|
|
|
<span class="info-label">运行状态</span>
|
|
<span class="info-label">运行状态</span>
|
|
|
<span class="info-value">
|
|
<span class="info-value">
|
|
@@ -117,6 +125,10 @@
|
|
|
</el-tag>
|
|
</el-tag>
|
|
|
</span>
|
|
</span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <div class="info-item">
|
|
|
|
|
+ <span class="info-label">维护人员</span>
|
|
|
|
|
+ <span class="info-value">{{ selectedDevice.maintainer }}</span>
|
|
|
|
|
+ </div>
|
|
|
<div class="info-item">
|
|
<div class="info-item">
|
|
|
<span class="info-label">上次维保</span>
|
|
<span class="info-label">上次维保</span>
|
|
|
<span class="info-value">{{ selectedDevice.lastMaintain }}</span>
|
|
<span class="info-value">{{ selectedDevice.lastMaintain }}</span>
|
|
@@ -161,7 +173,7 @@
|
|
|
<span class="ps-value" style="color:#10b981">{{ avgChartValue }}</span>
|
|
<span class="ps-value" style="color:#10b981">{{ avgChartValue }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- <div ref="deviceChartRef" style="width:100%;height:300px"></div>
|
|
|
|
|
|
|
+ <div ref="deviceChartRef" style="width:100%;height:280px"></div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -380,6 +392,7 @@
|
|
|
<script>
|
|
<script>
|
|
|
import { Search, Plus, Download, Minus } from '@element-plus/icons-vue'
|
|
import { Search, Plus, Download, Minus } from '@element-plus/icons-vue'
|
|
|
import * as echarts from 'echarts'
|
|
import * as echarts from 'echarts'
|
|
|
|
|
+import deviceImage from '@/assets/images/Heilin/image.png'
|
|
|
|
|
|
|
|
export default {
|
|
export default {
|
|
|
name: 'DeviceMaintainView',
|
|
name: 'DeviceMaintainView',
|
|
@@ -418,14 +431,14 @@ export default {
|
|
|
archivePage: 1,
|
|
archivePage: 1,
|
|
|
archiveTotal: 56,
|
|
archiveTotal: 56,
|
|
|
deviceArchive: [
|
|
deviceArchive: [
|
|
|
- { code: 'WL-001', name: '主坝水位计', category: '水位监测', model: 'WL-2000', location: '大坝坝顶', installDate: '2022-03-15', status: 'online', statusText: '在线', lastMaintain: '2026-04-10', nextMaintain: '2026-07-10' },
|
|
|
|
|
- { code: 'WL-002', name: '副坝水位计', category: '水位监测', model: 'WL-2000', location: '副坝坝顶', installDate: '2022-03-15', status: 'online', statusText: '在线', lastMaintain: '2026-04-10', nextMaintain: '2026-07-10' },
|
|
|
|
|
- { code: 'SP-001', name: '副坝渗压计', category: '渗流监测', model: 'SP-500', location: '副坝坝体', installDate: '2022-05-20', status: 'warning', statusText: '异常', lastMaintain: '2026-03-15', nextMaintain: '2026-06-15' },
|
|
|
|
|
- { code: 'GT-001', name: '溢洪道闸门', category: '闸门设备', model: 'ZM-3000', location: '溢洪道', installDate: '2021-11-08', status: 'online', statusText: '运行', lastMaintain: '2026-05-01', nextMaintain: '2026-08-01' },
|
|
|
|
|
- { code: 'FL-001', name: '入库流量计', category: '水位监测', model: 'FL-1500', location: '进水口', installDate: '2022-06-10', status: 'offline', statusText: '离线', lastMaintain: '2026-02-20', nextMaintain: '2026-05-20' },
|
|
|
|
|
- { code: 'VD-001', name: '大坝监控摄像头', category: '视频监控', model: 'HK-4K', location: '大坝坝顶', installDate: '2023-01-15', status: 'online', statusText: '在线', lastMaintain: '2026-05-10', nextMaintain: '2026-08-10' },
|
|
|
|
|
- { code: 'DM-001', name: '坝顶位移计', category: '变形监测', model: 'DM-100', location: '大坝坝顶', installDate: '2022-04-20', status: 'online', statusText: '在线', lastMaintain: '2026-04-25', nextMaintain: '2026-07-25' },
|
|
|
|
|
- { code: 'WT-001', name: '自动气象站', category: '气象监测', model: 'AWS-300', location: '管理区', installDate: '2022-08-01', status: 'maintenance', statusText: '维护中', lastMaintain: '2026-06-01', nextMaintain: '2026-09-01' }
|
|
|
|
|
|
|
+ { code: 'WL-001', name: '主坝水位计', category: '水位监测', model: 'WL-2000', brand: '华为', location: '大坝坝顶', installDate: '2022-03-15', installer: '张三', maintainer: '李四', status: 'online', statusText: '在线', lastMaintain: '2026-04-10', nextMaintain: '2026-07-10' },
|
|
|
|
|
+ { code: 'WL-002', name: '副坝水位计', category: '水位监测', model: 'WL-2000', brand: '华为', location: '副坝坝顶', installDate: '2022-03-15', installer: '张三', maintainer: '王五', status: 'online', statusText: '在线', lastMaintain: '2026-04-10', nextMaintain: '2026-07-10' },
|
|
|
|
|
+ { code: 'SP-001', name: '副坝渗压计', category: '渗流监测', model: 'SP-500', brand: '中兴', location: '副坝坝体', installDate: '2022-05-20', installer: '李四', maintainer: '赵六', status: 'warning', statusText: '异常', lastMaintain: '2026-03-15', nextMaintain: '2026-06-15' },
|
|
|
|
|
+ { code: 'GT-001', name: '溢洪道闸门', category: '闸门设备', model: 'ZM-3000', brand: '中信重工', location: '溢洪道', installDate: '2021-11-08', installer: '王五', maintainer: '张三', status: 'online', statusText: '运行', lastMaintain: '2026-05-01', nextMaintain: '2026-08-01' },
|
|
|
|
|
+ { code: 'FL-001', name: '入库流量计', category: '水位监测', model: 'FL-1500', brand: '西门子', location: '进水口', installDate: '2022-06-10', installer: '赵六', maintainer: '李四', status: 'offline', statusText: '离线', lastMaintain: '2026-02-20', nextMaintain: '2026-05-20' },
|
|
|
|
|
+ { code: 'VD-001', name: '大坝监控摄像头', category: '视频监控', model: 'HK-4K', brand: '海康威视', location: '大坝坝顶', installDate: '2023-01-15', installer: '张三', maintainer: '王五', status: 'online', statusText: '在线', lastMaintain: '2026-05-10', nextMaintain: '2026-08-10' },
|
|
|
|
|
+ { code: 'DM-001', name: '坝顶位移计', category: '变形监测', model: 'DM-100', brand: '基康', location: '大坝坝顶', installDate: '2022-04-20', installer: '李四', maintainer: '赵六', status: 'online', statusText: '在线', lastMaintain: '2026-04-25', nextMaintain: '2026-07-25' },
|
|
|
|
|
+ { code: 'WT-001', name: '自动气象站', category: '气象监测', model: 'AWS-300', brand: '华云', location: '管理区', installDate: '2022-08-01', installer: '王五', maintainer: '张三', status: 'maintenance', statusText: '维护中', lastMaintain: '2026-06-01', nextMaintain: '2026-09-01' }
|
|
|
],
|
|
],
|
|
|
// 维保记录
|
|
// 维保记录
|
|
|
maintainDateRange: null,
|
|
maintainDateRange: null,
|
|
@@ -525,7 +538,7 @@ export default {
|
|
|
return params[dev.code] || '—'
|
|
return params[dev.code] || '—'
|
|
|
},
|
|
},
|
|
|
getDeviceImage(dev) {
|
|
getDeviceImage(dev) {
|
|
|
- return '/src/assets/images/Heilin/image.png'
|
|
|
|
|
|
|
+ return deviceImage
|
|
|
},
|
|
},
|
|
|
initDeviceChart() {
|
|
initDeviceChart() {
|
|
|
if (!echarts) return
|
|
if (!echarts) return
|
|
@@ -561,14 +574,39 @@ export default {
|
|
|
this.avgChartValue = (data.reduce((a, b) => a + b, 0) / data.length).toFixed(2)
|
|
this.avgChartValue = (data.reduce((a, b) => a + b, 0) / data.length).toFixed(2)
|
|
|
const labelInterval = Math.max(1, Math.floor(dataPoints / 12))
|
|
const labelInterval = Math.max(1, Math.floor(dataPoints / 12))
|
|
|
const unitMap = { temperature: '℃', stress: 'MPa', displacement: 'mm', voltage: 'V' }
|
|
const unitMap = { temperature: '℃', stress: 'MPa', displacement: 'mm', voltage: 'V' }
|
|
|
|
|
+ const unitStr = unitMap[this.activeChartTab]
|
|
|
this.chartInstance.setOption({
|
|
this.chartInstance.setOption({
|
|
|
- animation: false, tooltip: { trigger: 'axis' },
|
|
|
|
|
|
|
+ animation: true,
|
|
|
|
|
+ tooltip: {
|
|
|
|
|
+ trigger: 'axis',
|
|
|
|
|
+ triggerOn: 'mousemove',
|
|
|
|
|
+ backgroundColor: 'rgba(255,255,255,0.95)',
|
|
|
|
|
+ borderColor: '#e2e8f0',
|
|
|
|
|
+ borderWidth: 1,
|
|
|
|
|
+ textStyle: { color: '#1e293b', fontSize: 12 },
|
|
|
|
|
+ formatter: function(params) {
|
|
|
|
|
+ const p = params[0]
|
|
|
|
|
+ if (!p) return ''
|
|
|
|
|
+ return '<div style="font-weight:600;margin-bottom:4px">' + p.axisValue + '</div>'
|
|
|
|
|
+ + '<div style="display:flex;align-items:center;gap:6px">'
|
|
|
|
|
+ + '<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:' + p.color + '"></span>'
|
|
|
|
|
+ + '<span style="font-weight:700">' + p.value + '</span>'
|
|
|
|
|
+ + '<span style="color:#94a3b8;margin-left:2px">' + unitStr + '</span>'
|
|
|
|
|
+ + '</div>'
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
grid: { left: 50, right: 20, top: 20, bottom: 30 },
|
|
grid: { left: 50, right: 20, top: 20, bottom: 30 },
|
|
|
- xAxis: { type: 'category', boundaryGap: false, data: timeList, axisLine: { lineStyle: { color: '#e5e7eb' } }, axisLabel: { color: '#94a3b8', fontSize: 10, interval: labelInterval } },
|
|
|
|
|
- yAxis: { type: 'value', name: unitMap[this.activeChartTab], nameTextStyle: { color: '#94a3b8', fontSize: 11 }, splitLine: { lineStyle: { color: 'rgba(0,0,0,0.04)' } }, axisLabel: { color: '#94a3b8', fontSize: 10 } },
|
|
|
|
|
|
|
+ xAxis: { type: 'category', boundaryGap: false, data: timeList,
|
|
|
|
|
+ axisLine: { lineStyle: { color: '#e5e7eb' } },
|
|
|
|
|
+ axisLabel: { color: '#94a3b8', fontSize: 10, interval: labelInterval },
|
|
|
|
|
+ axisPointer: { show: true, type: 'shadow', label: { show: true, formatter: function(p) { return p.value } } }
|
|
|
|
|
+ },
|
|
|
|
|
+ yAxis: { type: 'value', name: unitStr, nameTextStyle: { color: '#94a3b8', fontSize: 11 }, splitLine: { lineStyle: { color: 'rgba(0,0,0,0.04)' } }, axisLabel: { color: '#94a3b8', fontSize: 10 } },
|
|
|
dataZoom: [{ type: 'inside', start: 0, end: 100 }],
|
|
dataZoom: [{ type: 'inside', start: 0, end: 100 }],
|
|
|
series: [{
|
|
series: [{
|
|
|
- type: 'line', smooth: true, symbol: 'none', data: data,
|
|
|
|
|
|
|
+ type: 'line', smooth: true, symbol: 'circle', symbolSize: 6, showSymbol: false,
|
|
|
|
|
+ emphasis: { focus: 'series', lineStyle: { width: 3 }, itemStyle: { borderWidth: 3, borderColor: '#fff' } },
|
|
|
|
|
+ data: data,
|
|
|
lineStyle: { width: 2, color: this.chartColors[this.activeChartTab] },
|
|
lineStyle: { width: 2, color: this.chartColors[this.activeChartTab] },
|
|
|
itemStyle: { color: this.chartColors[this.activeChartTab] },
|
|
itemStyle: { color: this.chartColors[this.activeChartTab] },
|
|
|
areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: this.chartColors[this.activeChartTab] + '33' }, { offset: 1, color: this.chartColors[this.activeChartTab] + '05' }]) }
|
|
areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: this.chartColors[this.activeChartTab] + '33' }, { offset: 1, color: this.chartColors[this.activeChartTab] + '05' }]) }
|
|
@@ -740,26 +778,28 @@ export default {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* ==================== 设备详情弹窗 ==================== */
|
|
/* ==================== 设备详情弹窗 ==================== */
|
|
|
|
|
+.device-detail-dialog { padding: 15px; margin-top: 15px !important; margin-bottom: 15px !important; }
|
|
|
|
|
+.device-detail-dialog .el-dialog__body { padding: 16px 20px; }
|
|
|
.device-detail-body {
|
|
.device-detail-body {
|
|
|
- display: flex; flex-direction: column; gap: 20px;
|
|
|
|
|
|
|
+ display: flex; flex-direction: column; gap: 16px;
|
|
|
}
|
|
}
|
|
|
-.detail-top-row { display: flex; gap: 20px; }
|
|
|
|
|
-.detail-info-section { flex: 1; }
|
|
|
|
|
|
|
+.detail-top-row { display: flex; gap: 24px; }
|
|
|
|
|
+.detail-info-section { flex: 1; min-width: 0; }
|
|
|
.detail-info-header {
|
|
.detail-info-header {
|
|
|
font-size: 15px; font-weight: 600; color: #1e293b;
|
|
font-size: 15px; font-weight: 600; color: #1e293b;
|
|
|
margin-bottom: 12px; padding-bottom: 8px; border-bottom: 2px solid #3b82f6;
|
|
margin-bottom: 12px; padding-bottom: 8px; border-bottom: 2px solid #3b82f6;
|
|
|
}
|
|
}
|
|
|
.detail-info-grid {
|
|
.detail-info-grid {
|
|
|
- display: grid; grid-template-columns: 1fr 1fr; gap: 10px 20px;
|
|
|
|
|
|
|
+ display: grid; grid-template-columns: 1fr 1fr; gap: 12px 28px;
|
|
|
}
|
|
}
|
|
|
.info-item { display: flex; flex-direction: column; gap: 2px; }
|
|
.info-item { display: flex; flex-direction: column; gap: 2px; }
|
|
|
.info-label { font-size: 11px; color: #94a3b8; }
|
|
.info-label { font-size: 11px; color: #94a3b8; }
|
|
|
.info-value { font-size: 14px; font-weight: 500; color: #1e293b; }
|
|
.info-value { font-size: 14px; font-weight: 500; color: #1e293b; }
|
|
|
.detail-image-section {
|
|
.detail-image-section {
|
|
|
- width: 220px; flex-shrink: 0; display: flex; flex-direction: column; gap: 10px;
|
|
|
|
|
|
|
+ width: 260px; flex-shrink: 0; display: flex; flex-direction: column; gap: 10px;
|
|
|
}
|
|
}
|
|
|
.detail-image-frame {
|
|
.detail-image-frame {
|
|
|
- width: 220px; height: 150px; border-radius: 10px; overflow: hidden;
|
|
|
|
|
|
|
+ width: 100%; height: 170px; border-radius: 10px; overflow: hidden;
|
|
|
border: 1px solid #e2e8f0; background: #f8fafc;
|
|
border: 1px solid #e2e8f0; background: #f8fafc;
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
}
|
|
}
|
|
@@ -778,7 +818,7 @@ export default {
|
|
|
}
|
|
}
|
|
|
.chart-tab:hover { background: #e2e8f0; }
|
|
.chart-tab:hover { background: #e2e8f0; }
|
|
|
.chart-tab.active { background: #3b82f6; color: #fff; }
|
|
.chart-tab.active { background: #3b82f6; color: #fff; }
|
|
|
-.param-summary-row { display: flex; gap: 12px; margin-bottom: 10px; }
|
|
|
|
|
|
|
+.param-summary-row { display: flex; gap: 12px; margin-bottom: 10px; flex-shrink: 0; }
|
|
|
.param-summary-item {
|
|
.param-summary-item {
|
|
|
flex: 1; background: #fff; border-radius: 8px; padding: 8px 10px;
|
|
flex: 1; background: #fff; border-radius: 8px; padding: 8px 10px;
|
|
|
display: flex; flex-direction: column; align-items: center; gap: 2px;
|
|
display: flex; flex-direction: column; align-items: center; gap: 2px;
|
|
@@ -786,8 +826,6 @@ export default {
|
|
|
}
|
|
}
|
|
|
.ps-label { font-size: 11px; color: #94a3b8; }
|
|
.ps-label { font-size: 11px; color: #94a3b8; }
|
|
|
.ps-value { font-size: 18px; font-weight: 700; }
|
|
.ps-value { font-size: 18px; font-weight: 700; }
|
|
|
-.detail-chart-body { flex: 1; }
|
|
|
|
|
-
|
|
|
|
|
/* ==================== 分页 ==================== */
|
|
/* ==================== 分页 ==================== */
|
|
|
.pagination-wrap {
|
|
.pagination-wrap {
|
|
|
display: flex;
|
|
display: flex;
|